From 2ed703540d901eaf58427d0cf54fb0a5e68bc6a0 Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Fri, 26 Jun 2026 14:43:22 +0200 Subject: [PATCH] fix: don't reject `offline_access`scope --- .../controller/well_known_controller.go | 2 +- backend/internal/oidc/client.go | 2 +- tests/specs/oidc.spec.ts | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/backend/internal/controller/well_known_controller.go b/backend/internal/controller/well_known_controller.go index 5c7a2479..249fc341 100644 --- a/backend/internal/controller/well_known_controller.go +++ b/backend/internal/controller/well_known_controller.go @@ -84,7 +84,7 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) { "device_authorization_endpoint": appUrl + "/api/oidc/device/authorize", "jwks_uri": internalAppUrl + "/.well-known/jwks.json", "grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode, service.GrantTypeClientCredentials}, - "scopes_supported": []string{"openid", "profile", "email", "groups"}, + "scopes_supported": []string{"openid", "profile", "email", "groups", "offline_access"}, "claims_supported": []string{"sub", "given_name", "family_name", "name", "display_name", "email", "email_verified", "preferred_username", "picture", "groups", "auth_time", "amr"}, "response_types_supported": []string{"code", "id_token"}, "subject_types_supported": []string{"public"}, diff --git a/backend/internal/oidc/client.go b/backend/internal/oidc/client.go index 3623e238..67522bca 100644 --- a/backend/internal/oidc/client.go +++ b/backend/internal/oidc/client.go @@ -41,7 +41,7 @@ func (c Client) GetResponseTypes() fosite.Arguments { } func (c Client) GetScopes() fosite.Arguments { - return fosite.Arguments{"openid", "profile", "email", "groups"} + return fosite.Arguments{"openid", "profile", "email", "groups", "offline_access"} } func (c Client) IsPublic() bool { diff --git a/tests/specs/oidc.spec.ts b/tests/specs/oidc.spec.ts index f263e4b1..467f0390 100644 --- a/tests/specs/oidc.spec.ts +++ b/tests/specs/oidc.spec.ts @@ -57,6 +57,23 @@ test('Authorize new client', async ({ page }) => { ); }); +test('Authorize client requesting offline_access scope', async ({ page }) => { + const oidcClient = oidcClients.immich; + const urlParams = createUrlParams(oidcClient); + urlParams.set('scope', 'openid profile email offline_access'); + await page.goto(`/authorize?${urlParams.toString()}`); + + // offline_access is a valid OIDC scope: the flow must reach the consent screen rather than + // being rejected with invalid_scope (offline_access itself has no displayable scope item) + await expectScopes(page, ['Email', 'Profile']); + + const callbackUrl = await expectCallbackRedirect(page, oidcClient.callbackUrl, () => + page.getByRole('button', { name: 'Sign in' }).click() + ); + expect(callbackUrl.searchParams.get('code')).toBeTruthy(); + expect(callbackUrl.searchParams.get('error')).toBeNull(); +}); + test('Authorize new client while not signed in', async ({ page }) => { const oidcClient = oidcClients.immich; const urlParams = createUrlParams(oidcClient);