fix: pass XOAUTH2 token as str, not bytes (was corrupting the Bearer value)

aioimaplib's mail.xoauth2(user, token) builds the SASL string by f-string interpolating the token, so a bytes token injects the b'...' repr into auth=Bearer and breaks every XOAUTH2 login. dropped the .encode() (token is already str via _resolve_token/_as_str). corrected the inline comment and the CLAUDE.md note that both wrongly claimed bytes was required — that false note propagated the bug through prior review passes.

Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
disqualifier 2026-06-28 18:45:25 -04:00
parent 7934688595
commit 6ac8957583

View File

@ -85,12 +85,14 @@ class OAuth2Auth:
async def authenticate(self, mail) -> None:
token = await self._resolve_token()
# aioimaplib exposes mail.xoauth2(user, token: bytes) — note the token must
# be bytes, not str. older/other clients that lack it but expose a generic
# authenticate() are driven via the SASL string from _sasl_xoauth2.
# aioimaplib's mail.xoauth2(user, token) builds the SASL string by f-string
# interpolating the token, so token MUST be str — passing bytes interpolates
# the b'...' repr and corrupts the Bearer value. _resolve_token already
# returns str (via _as_str). clients lacking .xoauth2 are driven via the
# SASL callback from _sasl_xoauth2.
xoauth2 = getattr(mail, "xoauth2", None)
if xoauth2 is not None:
result, data = await xoauth2(self.user, token.encode())
result, data = await xoauth2(self.user, token)
elif hasattr(mail, "authenticate"):
result, data = await mail.authenticate(
"XOAUTH2", lambda _: _sasl_xoauth2(self.user, token)