sasl: wire OAUTHBEARER (RFC 7628) alongside IRCV3BEARER#202
Conversation
The cap was originally REQ'd in commit 25bc958 (May 2025) but was silently dropped during the refactor in 3508ddf and has been missing ever since. We populate the member list from WHO/WHOX on JOIN, so the implicit RPL_NAMREPLY burst is wasted bandwidth. Request both the ratified `no-implicit-names` cap and the original `draft/no-implicit-names` name for back-compat with servers that haven't moved to the ratified form yet.
Ergo follows IRCv3 SASL-3.1 literally: the client must send "AUTHENTICATE +" to indicate "no more data from me" before Ergo emits 903. Without that ack the SASL session hangs and the connection times out. UnrealIRCd, by contrast, immediately follows server-final with either 903 or "AUTHENTICATE 2FA-REQUIRED"; in the latter case our "+" would be read as an empty TOTP code and trip 904 (regression that prompted b096e0b "Don't send spurious AUTHENTICATE +"). Schedule the ack 750 ms after server-final and skip if either: - CAP negotiation has completed (903 already arrived) - The 2FA step-up handler marked stepupStarted on the session An epoch counter on the session guards against a fresh SASL run on the same serverId firing the stale timer. Reported on irc.h4ks.com (Ergo); confirmed unaffected on obbyircd.
The buildOauthBearerPayload frame builder has existed in saslFrames.ts since the OAuth feature landed, but nothing called it: the SaslMech union, chooseMechanism, and the AUTHENTICATE dispatch all only knew IRCV3BEARER. On networks that only advertise the SASL-WG OAUTHBEARER (RFC 7628) -- as opposed to obbyircd-style IRCV3BEARER -- OAuth login silently failed. - Add "OAUTHBEARER" to SaslMech. - Primary-mech selection prefers IRCV3BEARER (richer: token_type + provider hint, used for 2FA step-up) and falls back to OAUTHBEARER if only the latter is advertised. - Stash the server host/port on the SaslSession so we can populate the optional gs2-header host=/port= keys at AUTHENTICATE time. - Dispatch branch builds the RFC 7628 GS2 payload and chunks it into 400-byte AUTHENTICATE blocks like every other multi-line mech. 2FA step-up remains IRCV3BEARER-only because OAUTHBEARER doesn't carry the token_type / provider info obbyircd needs to route the bearer.
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis change extends the authentication handler to support RFC 7628 OAUTHBEARER as a SASL mechanism for OAuth-only logins. During SASL negotiation, the code chooses between IRCV3BEARER (if advertised) or OAUTHBEARER (fallback), captures server host/port hints, and later constructs GS2-framed OAuth bearer payloads in the AUTHENTICATE handler. ChangesOAUTHBEARER SASL Mechanism Support
Sequence DiagramsequenceDiagram
participant Client
participant Server
participant AuthHandler
Client->>Server: CAP REQ sasl
Server->>Client: CAP ACK sasl (advertises mechanisms)
AuthHandler->>AuthHandler: Check OAuth bearer + advertised mechs
alt IRCV3BEARER advertised
AuthHandler->>AuthHandler: Select IRCV3BEARER
else OAUTHBEARER advertised
AuthHandler->>AuthHandler: Select OAUTHBEARER
end
AuthHandler->>AuthHandler: Capture oauthHost, oauthPort from config
AuthHandler->>AuthHandler: Initialize SaslSession with chosen mech
AuthHandler->>Server: AUTHENTICATE <chosen-mech>
Server->>Client: +
alt mech === OAUTHBEARER
AuthHandler->>AuthHandler: Build GS2-framed payload (bearer token + hints)
AuthHandler->>AuthHandler: Chunk payload
AuthHandler->>Server: AUTHENTICATE <chunk>
end
Server->>Client: SASL negotiation completes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Automated deployment preview for the PR in the Cloudflare Pages. |
Summary
`buildOauthBearerPayload` has existed in src/lib/saslFrames.ts since the OAuth feature landed, but it had no call site. The `SaslMech` union, `chooseMechanism`, and the AUTHENTICATE dispatch only knew `IRCV3BEARER`. So on networks that advertise the SASL-WG `OAUTHBEARER` (RFC 7628) but not the obbyircd-style `IRCV3BEARER`, OAuth login silently fell off the mech-selection path.
Changes
2FA step-up remains `IRCV3BEARER`-only since OAUTHBEARER doesn't carry the `token_type` + provider info obbyircd needs to route the bearer through opaque/userinfo resolution. Servers that only advertise OAUTHBEARER don't have obbyircd's step-up flow anyway.
Test plan
Summary by CodeRabbit