Describe the bug
Description
ServicePulse assembles its OIDC scope request client-side, appending a fixed suffix to the configured API scope:
// src/Frontend/src/stores/AuthStore.ts:64
scope: `${apiScope} openid profile email offline_access`,
offline_access is hard-coded here rather than coming from ServiceControl's AuthenticationController.Configuration() response, which is where every other part of the OIDC client configuration (authority, client ID, audience, API scopes) comes from. Not all identity providers permit offline_access for a given client, and there is currently no way to stop ServicePulse requesting it.
Particular/ServiceControl#5633 proposes that ServiceControl compose the full scope string (including whether offline_access is present, controlled by a new Authentication.ServicePulse.OfflineAccessScopeEnabled setting) and expose it as Scopes on AuthConfig. This issue tracks the companion ServicePulse change to consume that value instead of assembling the scope string itself.
Expected behavior
ServicePulse uses the scope string returned by ServiceControl's auth configuration when present. When talking to an older ServiceControl that doesn't return it, ServicePulse falls back to its current behaviour of assembling api_scopes plus openid profile email offline_access, so existing deployments are unaffected.
Actual behavior
offline_access is always requested, with no way for an operator to opt out short of editing ServicePulse's source. When the configured identity provider doesn't permit offline_access for the client, the authorization request is rejected outright and the user never reaches a login page - the failure is total, not degraded, and the resulting error doesn't identify offline_access as the cause.
Versions
Applies to all current ServicePulse versions that use AuthStore.ts for OIDC sign-in. Depends on the corresponding ServiceControl change in #5633 being available before there is a Scopes field to consume.
Steps to reproduce
- Configure ServicePulse's identity provider connection against a client/app registration that does not permit the
offline_access scope.
- Attempt to sign in to ServicePulse.
- Observe that the authorization request fails before reaching the identity provider's login page, since
offline_access is unconditionally included in the requested scope and there is no configuration option to remove it.
Relevant log output
N/A
Additional Information
Workarounds
None available through configuration. Removing offline_access currently requires a source change to AuthStore.ts.
Possible solutions
Additional information
From #5633: without offline_access, some identity providers don't issue a refresh token, so ServicePulse falls back to a hidden iframe silent-renew against the IdP session cookie. Browsers that restrict third-party cookies (Safari ITP, Brave, Chrome's ongoing restrictions) will fail that request, forcing a full-page re-authentication redirect at every token expiry - with a live IdP session this is a brief round-trip that loses in-app state, and without one the user is dropped back to the login page mid-session. This is a secondary reason to keep offline_access enabled by default and make disabling it an explicit, informed operator choice.
Describe the bug
Description
ServicePulse assembles its OIDC scope request client-side, appending a fixed suffix to the configured API scope:
offline_accessis hard-coded here rather than coming from ServiceControl'sAuthenticationController.Configuration()response, which is where every other part of the OIDC client configuration (authority, client ID, audience, API scopes) comes from. Not all identity providers permitoffline_accessfor a given client, and there is currently no way to stop ServicePulse requesting it.Particular/ServiceControl#5633 proposes that ServiceControl compose the full scope string (including whether
offline_accessis present, controlled by a newAuthentication.ServicePulse.OfflineAccessScopeEnabledsetting) and expose it asScopesonAuthConfig. This issue tracks the companion ServicePulse change to consume that value instead of assembling the scope string itself.Expected behavior
ServicePulse uses the scope string returned by ServiceControl's auth configuration when present. When talking to an older ServiceControl that doesn't return it, ServicePulse falls back to its current behaviour of assembling
api_scopesplusopenid profile email offline_access, so existing deployments are unaffected.Actual behavior
offline_accessis always requested, with no way for an operator to opt out short of editing ServicePulse's source. When the configured identity provider doesn't permitoffline_accessfor the client, the authorization request is rejected outright and the user never reaches a login page - the failure is total, not degraded, and the resulting error doesn't identifyoffline_accessas the cause.Versions
Applies to all current ServicePulse versions that use
AuthStore.tsfor OIDC sign-in. Depends on the corresponding ServiceControl change in #5633 being available before there is aScopesfield to consume.Steps to reproduce
offline_accessscope.offline_accessis unconditionally included in the requested scope and there is no configuration option to remove it.Relevant log output
N/A
Additional Information
Workarounds
None available through configuration. Removing
offline_accesscurrently requires a source change toAuthStore.ts.Possible solutions
offline_accessscope in the ServicePulse auth configuration ServiceControl#5633, which proposes exposing a composedScopesvalue onAuthConfig.AuthStore.tsto use the scope string from ServiceControl's auth configuration when present, falling back to the current hard-coded construction (${apiScope} openid profile email offline_access) when it is absent, for compatibility with older ServiceControl versions.Additional information
From #5633: without
offline_access, some identity providers don't issue a refresh token, so ServicePulse falls back to a hidden iframe silent-renew against the IdP session cookie. Browsers that restrict third-party cookies (Safari ITP, Brave, Chrome's ongoing restrictions) will fail that request, forcing a full-page re-authentication redirect at every token expiry - with a live IdP session this is a brief round-trip that loses in-app state, and without one the user is dropped back to the login page mid-session. This is a secondary reason to keepoffline_accessenabled by default and make disabling it an explicit, informed operator choice.