From b1884829fef69f42cd3d26d38d58812b0114b0b4 Mon Sep 17 00:00:00 2001 From: dankelleher Date: Sun, 22 Jun 2025 13:43:23 +0200 Subject: [PATCH] Add prompt=consent for offline_access scope in OIDC flow --- src/client/auth.test.ts | 14 ++++++++++++++ src/client/auth.ts | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/src/client/auth.test.ts b/src/client/auth.test.ts index f95cb2ca8..f9d714ef7 100644 --- a/src/client/auth.test.ts +++ b/src/client/auth.test.ts @@ -394,6 +394,20 @@ describe("OAuth Authorization", () => { expect(authorizationUrl.searchParams.has("state")).toBe(false); }); + // OpenID Connect requires that the user is prompted for consent if the scope includes 'offline_access' + it("includes consent prompt parameter if scope includes 'offline_access'", async () => { + const { authorizationUrl } = await startAuthorization( + "https://auth.example.com", + { + clientInformation: validClientInfo, + redirectUrl: "http://localhost:3000/callback", + scope: "read write profile offline_access", + } + ); + + expect(authorizationUrl.searchParams.get("prompt")).toBe("consent"); + }); + it("uses metadata authorization_endpoint when provided", async () => { const { authorizationUrl } = await startAuthorization( "https://auth.example.com", diff --git a/src/client/auth.ts b/src/client/auth.ts index d953e1f0a..c96d5a540 100644 --- a/src/client/auth.ts +++ b/src/client/auth.ts @@ -395,6 +395,13 @@ export async function startAuthorization( authorizationUrl.searchParams.set("scope", scope); } + if (scope?.includes("offline_access")) { + // if the request includes the OIDC-only "offline_access" scope, + // we need to set the prompt to "consent" to ensure the user is prompted to grant offline access + // https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess + authorizationUrl.searchParams.append("prompt", "consent"); + } + if (resource) { authorizationUrl.searchParams.set("resource", resource.href); }