/images/resources/code-examples/code-examples-javascript.jpg

Javascript SPA using Assisted Token Flow

On this page

Note

Curity Identity Server is used in this example, but other OAuth servers can also be used.

Overview

This tutorial will describe how to run a code example that uses the Assisted Token Flow for a plain Javascript SPA. Once understood, the principles can be applied to any technology stack. The result is simple, secure and reliable, while also providing a good login user experience.

Best Practice Update

For best results and strongest security it is no longer recommended to implement OAuth for your production SPAs solely in Javascript. See the SPA security best practices for an alternative design.

The assisted token flow may also be impacted by recent same-site cookie restrictions, if the user agent no longer sends the required cookies. See the OAuth cookie best practices article for further information.

Download the Code

Get the code from this page's GitHub link, and the SPA will run on a base URL of http://localhost:8080. The SPA is configured to use a Javascript OAuth library from the Identity Server, so ensure that the SPA's index.html file uses the correct URL for your environment:

  • Client ID = client-assisted-example
  • Assisted Token Script URL: https://localhost:8443/oauth/v2/oauth-assisted-token/resources/js/assisted-token.min.js

This article will describe some details of the Assisted Token API, and for full details you can consult the Assisted Token Library API Reference.

Configure Identity Server

Next we need to configure an OAuth Client in the Identity Server Admin UI, and we will start by ensuring that Assisted Token Flow is active under the Token Service Profile:

Assisted Token Enabled

Next use the Admin UI to create an OAuth Client with the following settings:

  • Client ID: client-assisted-example
  • Capabilities: Assisted Token
  • Allowed Origins: http://localhost:8080
  • OAuth + OpenID Settings / Scope: openid

Run the Code Sample

Next we will run the code sample, perform OAuth operations to get tokens, and use the tokens to call a demo API endpoint:

  • Run node server.js to serve the SPA's index.html page and to expose a simple API endpoint
  • Navigate to http://localhost:8080 in a browser
  • Open browser tools in order to view HTTP messages sent by the SPA
Code Sample

1. User Authentication

The first step in our OAuth secured SPA is to sign the user in and return OAuth tokens to the SPA. The assisted token flow uses secure iframing to perform login via a modal dialog. This provides a good user experience since it avoids disrupting the end user and redirecting the entire browser window:

Login UX

Technically, two messages are sent, the first of which is a request for a token and, if the user is not authenticated, there follows an authentication redirect:

1
https://localhost:8443/oauth/v2/oauth-assisted-token/token?client_id=client-assisted-example&for_origin=http://localhost:8080
1
https://localhost:8443/authn/authentication?serviceProviderId=token-service&client_id=client-assisted-example&resumePath=%2Foauth%2Fv2%2Foauth-assisted-token%2Ftoken&state=R_dI8eDV9yYckHSZaGbuOOzZ0Lhht1upUJ

The message handling complexity is managed by the Assisted Token library. The SPA itself only needs to use an assistant object and provide a single line of code:

javascript
1
await assistant.loginIfRequired();

The end result is that the SPA now has an opaque access token that can be sent to an API. In addition the Identity Server issues a session cookie that is used later when performing token refresh or signing the user out.

Logged In

2. Call an API with the Access Token

An SPA would typically then send the access token to APIs during the user's authenticated session. The assisted token library takes care of overriding the XmlHttpRequest and adding the bearer token to the Authorization Header:

Call API

3. Silently Refresh Tokens

Access tokens should be configured to be short lived, with a lifetime such as 30 minutes, whereas the user's authentication session might last longer, such as for a few hours. Also, the OAuth assistant is an object that exists only in browser memory, meaning that there are 3 potential reasons for a token refresh operation:

  • The access token expires and a 401 response is received from an API call
  • The browser tab is reloaded with an option such as Command-R or F5
  • The user performs multi tab browsing within the SPA

The third code sample option can be used to manage these scenarios, and attempts to silently renew an access token. This works by sending the session cookie to the Identity Server in a request for a new token:

1
https://localhost:8443/oauth/v2/oauth-assisted-token/token?client_id=client-assisted-example&for_origin=http://localhost:8080
Call API

If the user's authenticated session is still valid, this request will return a new access token, as above. Otherwise the SPA client must instead handle the error response, typically by again calling the login operation on the OAuth assistant to ask the user to re-authenticate.

4. Force Re-Authentication

The fourth example option shows how to trigger an OAuth redirect that forces the user to re-authenticate. This would most commonly be used to get an access token with different / high privilege scopes, such as those for a payment operation:

Call API

OAuth scopes are specified in a settings object, as described in the API reference, and a new assistant object can be created with an additional scope if needed:

javascript
1234567
var settings = {
clientId: "client-assisted-example",
autoPrepareJqueryAjaxForOrigins: ['^/.*$'],
scope: 'openid profile payment',
}
var assistant = curity.token.assistant(settings);
await assistant.loginIfRequired();

5. Logout

Finally the assisted token library has a logout operation, which removes the SSO session cookie and revokes access tokens for the user. The following two messages are sent by the assisted token library to achieve this:

1
https://localhost:8443/oauth/v2/oauth-assisted-token/revoke?client_id=client-assisted-example&for_origin=http://localhost:8080
1
https://localhost:8443/authn/authentication/logout?serviceProviderId=token-service&client_id=client-assisted-example&for_origin=http://localhost:8080
Call API

Third Party Cookies

The Assisted Token Flow relies on the ability of the Identity Server to set an SSO cookie for the SPA, which the browser will then treat as a 'Third Party Cookie'. Recent changes to the below browsers may however lead to the SSO cookie being dropped with the default configuration:

  • Safari browser / Preferences / Privacy / Prevent Cross Site Tracking
  • Chrome Incognito browser / Settings / Privacy and Security / Cookies and other site data / Block third-party cookies in Incognito

For options on dealing with this, see the Assisted Token Library API Reference and the notes on preflighting.

Conclusion

The assisted token flow can be used to quickly implement OAuth for a Single Page Application, and to deal with tricky behavior. This enables secure SPAs with a good user experience and with only simple code. It is also being proposed as a Draft Standards Specification.

Join our Newsletter

Get the latest on identity management, API Security and authentication straight to your inbox.

Start Free Trial

Try the Curity Identity Server for Free. Get up and running in 10 minutes.

Start Free Trial