React SPA using Assisted Token Flow
On this page
Note
The example uses the Curity Identity Server, but you can run the code against any standards-based authorization server.
Overview
An example React application capable of acquiring an access token from the Curity Identity Server using the assisted token flow. The example code contains a Single Page Application for acquiring the token and an example API which can be called from the SPA using the access token.
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.
Configure the Identity Server
In the Curity Identity Server, create an OAuth client with the following details, and also ensure that at least one working authenticator is configured against the client:
- Client ID:
client-assisted-example
- Capabilities: Assisted Token Flow + Implicit Flow
- Allowed Origins:
http://localhost:3000
- Redirect URI:
http://localhost:3000
- OAuth + OpenID Settings / Scope:
openid
Configure the SPA
The React SPA can be downloaded from the GitHub link on this page and will then run at http://localhost:3000
by default. Edit the constants.js
file in the SPA and set details to match your environment:
export const ISSUER = "https://localhost:8443/";export const CLIENT_ID = "client-assisted-example";export const API_URL = "http://127.0.0.1:8100";export const AUTH_SERVER_ORIGIN = "http://127.0.0.1:8100";export const OPENID_CONFIGURATION_URL = 'oauth/v2/oauth-anonymous/.well-known/openid-configuration'.
The SPA will use the Assisted Token Endpoint from the Curity Identity Server, and will download a library from a URL such as this at runtime:
https://localhost:8443/oauth/v2/oauth-assisted-token/resources/js/assisted-token.min.js
The SPA will then use the window.curity.token.assistant
Javascript object to perform OAuth operations.
Run the SPA
Now that the setup is complete you can run npm install
then npm start
to browse to the SPA at http://localhost:3000
. When the page loads, it makes an initial full screen redirect to the Identity Server in order to act as a user gesture, so that SSO cookies are then persisted by the browser. This is done in the App.js source file in the checkAuthorization method:
window.location.href = this.config.authorization_endpoint +`?response_type=id_token&scope=openid&client_id=${CLIENT_ID}` +`&redirect_uri=${window.origin}&prompt=none&nonce=${nonce}`;
Perform a Login
Next click the Login button to trigger sign in via an iframe, to prompt the end user to authenticate. The sample then uses secure iframing to invoke a login window without disrupting the current state within the SPA:
Triggering the login request only requires a single line of code when using the assisted token library, after which tokens are returned to the SPA:
this.tokenAssistant.loginIfRequired().then((msg) => {this.userToken = this.tokenAssistant.getAuthHeader();}
Once login is complete, an authenticated session begins, and this is represented by an SSO cookie that the Identity Server issues to the SPA. This cookie is used by the assisted token library to retrieve tokens silently while the user's authenticated session remains valid.
Call an API from the React SPA
After user sign in, the code sample provides a minimal screen as follows, to show the token returned from login and sent to the sample's API:
The sample uses the popular axios library to call the API and note that the assisted token library manages overriding the XmlHttpRequest and adding the access token to the Authorization header in the correct manner.
callApi() {const isUserAuthenticated = this.tokenAssistant.isAuthenticated() && !this.tokenAssistant.isExpired();if (isUserAuthenticated) {axios.get(API_URL + '/api').then(response => {this.apiResponse = response.data.data;}else {this.tokenAssistant.loginIfRequired().then((token) => {this.callApi();}
The assisted token library also helps to deal with access token expiry conditions. If a token is expired or a 401 response is received from the API, the SPA can call loginIfRequired
again to attempt to silently refresh the token, or to prompt the user to re-authenticate if the SSO cookie has expired.
API Cross Origin Request Handling
The React code example includes a simple Node.js API which runs at http://localhost:8100
and is implemented in the server.js
file. The API operation simply echoes the token back to the UI for display, but the API code shows how to set API response headers so that the browser is allowed to make cross-origin calls to the API:
var origin = request.headers["origin"];if (request.method === 'OPTIONS') {responseHeaders['Access-Control-Allow-Origin'] = origin;responseHeaders['Access-Control-Allow-Methods'] = "GET, HEAD, OPTIONS";responseHeaders['Access-Control-Allow-Headers'] = 'Authorization, WWW-Authenticate, Content-Type';responseHeaders["Access-Control-Allow-Credentials"] = "true";responseHeaders["Allow"] = "GET, HEAD, OPTIONS";response.writeHead(200, responseHeaders);response.end();}else {responseHeaders["Access-Control-Allow-Origin"] = origin;responseHeaders["Access-Control-Allow-Credentials"] = "true";}
Lifecycle Events
The React SPA is only a basic sample to show how to fit the Assisted Token flow into a React coding style. For further details on dealing with lifecycle events, see the Javascript Assisted Token Sample, which covers aspects such as token refresh and multi tab browsing.
Conclusion
The Assisted Token Flow can be easily integrated into a React SPA, and adapted to the React coding style. For further programming details, see the Assisted Token Library API Reference.
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