Skip to content

fix: don't abort on LOGINDISABLED when XOAUTH2 is configured - #2

Merged
Martin Zaloudek (ma-zal) merged 2 commits into
masterfrom
mazal/fix-logindisabled-xoauth2
Aug 25, 2026
Merged

fix: don't abort on LOGINDISABLED when XOAUTH2 is configured#2
Martin Zaloudek (ma-zal) merged 2 commits into
masterfrom
mazal/fix-logindisabled-xoauth2

Conversation

@ma-zal

Copy link
Copy Markdown

LOGINDISABLED (RFC 3501 §6.2.3) only forbids the LOGIN command — SASL mechanisms advertised as AUTH=* stay available. But _login() checked LOGINDISABLEDbefore selecting the auth mechanism, so it aborted unconditionally, even when an XOAUTH/XOAUTH2 token was configured and the server advertised AUTH=XOAUTH2.

This broke every OAuth-based IMAP connection to Exchange Online. Microsoft has permanently disabled Basic authentication for IMAP in all tenants; such mailboxes answer CAPABILITY with LOGINDISABLED and without AUTH=PLAIN, leaving AUTH=XOAUTH2 as the only usable mechanism. Captured by the Microsoft Remote Connectivity Analyzer against outlook.office365.com:993, where the mailbox itself is healthy:

S: * CAPABILITY IMAP4 IMAP4rev1 AUTH=XOAUTH2 LOGINDISABLED SASL-IR UIDPLUS MOVE ID
UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
C: 2 AUTHENTICATE XOAUTH2 ********
S: 2 OK AUTHENTICATE completed.

Behaviour with new Imap({ xoauth2: '<token>', host: 'outlook.office365.com', port: 993, tls: true }) against that server:

BeforeAfter
Command after CAPABILITY(none, aborted)AUTHENTICATE XOAUTH2 <token>
Eventerror: Logging in is disabled on this serverready

The check now runs inside the LOGIN branch, so a client that can only use LOGIN still fails early and never puts credentials on the wire. The STARTTLS / autotls: 'required' decision above it is unchanged.

Two tests added: test-connection-logindisabled-xoauth2.js (XOAUTH2 succeeds despite LOGINDISABLED; verified to fail without this fix) and test-connection-logindisabled-login.js (LOGIN still refused, no credentials sent).

https://make.atlassian.net/browse/IEN-16426

Written by 🤖 Claude Code AI, reviewed by Martin Zaloudek (@ma-zal)

LOGINDISABLED (RFC 3501) only forbids the LOGIN command; SASL mechanisms
advertised as AUTH=* stay available. _login() checked it before selecting
the auth mechanism, so it aborted unconditionally even when an
XOAUTH/XOAUTH2 token was configured.
Exchange Online advertises LOGINDISABLED together with AUTH=XOAUTH2 once
basic auth is disabled for a mailbox, which made every OAuth-based IMAP
connection fail with "Logging in is disabled on this server".
The check now runs inside the LOGIN branch, so clients that can only use
LOGIN still fail before any credentials reach the wire.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CopilotAI lite review requested due to automatic review settings August 25, 2026 10:03

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes OAuth-based IMAP authentication against servers that advertise LOGINDISABLED (notably Exchange Online) by ensuring LOGINDISABLED only blocks the LOGIN command, not SASL AUTHENTICATE mechanisms like XOAUTH/XOAUTH2.

Changes:

  • Move the LOGINDISABLED check into the LOGIN (user/password) branch so XOAUTH/XOAUTH2 can still be attempted when available.
  • Add regression tests covering (1) XOAUTH2 success despite LOGINDISABLED and (2) LOGIN refusal with no credentials sent.
  • Bump package version to 0.8.23 and add a fork-specific CHANGELOG.md entry documenting the fix.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
lib/Connection.jsAdjusts _login() flow so LOGINDISABLED only blocks LOGIN, not XOAUTH/XOAUTH2 AUTHENTICATE.
test/test-connection-logindisabled-xoauth2.jsNew test ensuring XOAUTH2 proceeds and reaches ready even when LOGINDISABLED is advertised.
test/test-connection-logindisabled-login.jsNew test ensuring LOGIN is blocked early and credentials are not sent when LOGINDISABLED is advertised.
package.jsonVersion bump to 0.8.23.
CHANGELOG.mdAdds fork changelog entry documenting the behavior change and references.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ma-zal
Martin Zaloudek (ma-zal) merged commit 70f48f5 into masterAug 25, 2026
1 check passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@ma-zal@thomashampl