Skip to main content

Single sign-on for single-page applications

This page explains how to set up single sign-on (SSO) for single-page applications (SPAs) that use nevisAuth as an OpenID Provider. After the user logs in to one SPA, other SPAs get tokens without a new login. The same applies when a SPA renews expired tokens.

SSO depends on the session that nevisProxy keeps for the browser. The session cookie of this SSO session must reach the authorization endpoint. It must not reach the token endpoint.

Preconditions​

nevisAuth answers a token request as the client, not as the user. After the response, nevisAuth tells nevisProxy to end the session of the token request. This is intentional: a client does not need a session at the token endpoint.

A server-side client sends the token request without the cookies of the browser. The token request then has its own short-lived session, and only this session ends.

A SPA sends the token request from the browser with fetch. If the browser adds the SSO session cookie, the token request arrives in the SSO session of the user. nevisProxy does not accept the change from the user to the client in an authenticated session. It ends the SSO session and returns HTTP status 403. The SPA gets no tokens, and the next authorization request needs a new login.

For this reason, send the token request without the SSO session cookie.

Whether the browser sends the cookie depends on the credentials option of fetch and on the origins of the SPA and the token endpoint:

SPA and token endpointcredentials valueCookie sentResult
Same origin, for example https://www.example.com/app and https://www.example.com/oauth/tokensame-origin (default) or includeYesToken request fails, SSO session ends
Same originomitNoTokens, SSO session stays
Different origins, for example https://app.example.com and https://login.example.comsame-origin (default) or omitNoTokens, SSO session stays
Different originsincludeYesToken request fails, SSO session ends

The table applies when the SPA and nevisProxy are on the same site, for example both on example.com. On different sites, the SameSite attribute of the cookie can also stop the browser from sending it.

note

The Allowed Origins setting of the authorization server does not prevent the browser from sending the cookie. The browser sends a form-encoded token request without a preflight request. The CORS response headers then only control whether the SPA can read the response, and nevisProxy has already ended the session.

Choosing an approach​

ApproachUse whenWhat the SPA does
Backend for frontend (BFF)You can run a server-side component for the SPA.Calls its backend. The backend is a confidential client and sends the token request from the server.
Token request without credentialsThe SPA is a public client and gets the tokens itself.Sends the token request with credentials: 'omit'. On a different origin, the default credentials value also works.
Refresh tokensThe SPA must renew tokens without the SSO session.Requests the offline_access scope and renews tokens with the refresh token. The refresh request needs no session.

A BFF is the most secure approach, because the tokens never reach the browser. If the SPA gets the tokens itself, verify the credentials setting of your OpenID Connect client library. If the SPA uses refresh tokens, enable Refresh Token Rotation after confirming that every client on this authorization server handles rotated tokens, and store refresh tokens securely.

You can combine the approaches. For example, a SPA can send the token request without credentials and also use refresh tokens.

Configuring the authorization server​

To let SPAs get tokens without a new login while the SSO session is active, enable the prompt parameter:

  1. In nevisAdmin 4, open the OAuth 2.0 Authorization Server / OpenID Provider pattern.
  2. In Custom Properties, add the key openid.promptParameterSupported with the value true.
  3. Deploy the configuration.
info

Use prompt=none with nevisAuth 9.2605.1 or later, or with nevisAuth 8.2607 LTS. Earlier versions do not handle prompt=none without an active session correctly.

With this property set to true, nevisAuth handles the prompt parameter of the authorization request as follows:

prompt valueActive SSO sessionNo active SSO session
noneRedirect to the client with a new authorization code. There is no login and no consent screen. The auth_time claim keeps the time of the original login.Redirect to the client with the error login_required.
loginLogin screenLogin screen
Other values, for example consentIgnoredIgnored

Without the property, nevisAuth ignores the prompt parameter. A prompt=none request without an active session then shows the login screen instead of returning login_required.

If you configure the AuthorizationServer AuthState without nevisAdmin 4, set the property directly, see AuthorizationServer.

Configuring the SPA client in nevisMeta​

In the nevisMeta Web Console, configure the SPA client as follows. For the field descriptions, see Entities.

  • Type: PUBLIC
  • Token Endpoint Auth Method: NONE. A SPA cannot keep a client secret.
  • PKCE Mode: s256-required
  • Registered Scopes: openid, and offline_access if the SPA uses refresh tokens.
  • Policies: do not enable Force re-authentication. It requires a login on every authorization request, also with an active SSO session.

If the scopes of the SPA require consent, the user sees the consent screen at the first interactive authorization request of each SPA.

For a BFF, configure the backend as a CONFIDENTIAL client with a client secret instead.

Troubleshooting SSO for SPAs​

SymptomCauseSolution
The token request returns HTTP status 403 with the page Blocked Request, and the next authorization request needs a new login. The nevisProxy log contains received corrupted SecToken: changed userID,sessionID [AUTH-0031].The token request carried the SSO session cookie. In the developer tools of the browser, the token request has a Cookie header.Send the token request without credentials, or use a BFF.
A prompt=none request shows the login screen.openid.promptParameterSupported is not set to true.Add the property in Custom Properties.
A prompt=none request in a hidden iframe always returns login_required.The browser blocks the SSO session cookie in third-party context. This happens when the SPA and nevisProxy are on different sites.Send the prompt=none request as a top-level redirect, host the SPA and nevisProxy on the same site, or use refresh tokens.