Fix Microsoft OAuth callback by passing scope in token exchange

Microsoft's v2.0 token endpoint requires a 'scope' parameter in the
authorization code exchange request. The openid-client library does not
include it automatically since it is optional per RFC 6749.

Pass scope via the exchangeBody extras parameter for all providers'
callback and oauthCallback calls. Also forward the provider-specific
extra scope from the outer OAuth info to the token exchange.

Co-Authored-By: Konstantin Wohlwend <n2d4xc@gmail.com>
This commit is contained in:
Devin AI 2026-05-27 23:01:01 +00:00
parent c0fefd3b7a
commit ab1efa2b28
2 changed files with 10 additions and 2 deletions

View File

@ -168,6 +168,7 @@ const handler = createSmartRouteHandler({
callbackResult = await providerObj.getCallback({
codeVerifier: innerCodeVerifier,
state: innerState,
extraScope: providerScope,
callbackParams: {
...query,
...body,

View File

@ -386,6 +386,7 @@ export abstract class OAuthBaseProvider {
callbackParams: CallbackParamsType,
codeVerifier: string,
state: string,
extraScope?: string,
}): Promise<{ userInfo: OAuthUserInfo, tokenSet: TokenSet }> {
let tokenSet;
const callbackParams = { ...options.callbackParams };
@ -410,11 +411,17 @@ export abstract class OAuthBaseProvider {
},
] as const;
const callbackExtras = {
exchangeBody: {
scope: mergeScopeStrings(this.scope, options.extraScope ?? ""),
},
};
try {
if (this.openid) {
tokenSet = await this.oauthClient.callback(...params);
tokenSet = await this.oauthClient.callback(...params, callbackExtras);
} else {
tokenSet = await this.oauthClient.oauthCallback(...params);
tokenSet = await this.oauthClient.oauthCallback(...params, callbackExtras);
}
} catch (error: any) {
if (error?.error === "invalid_grant" || error?.error?.error === "invalid_grant") {