Previously we decided to update to the correct Open Id Connect flow for an SPA and use Id Tokens. We will now complete the Usability features, which are primarily related to Session Management.
Getting the Latest Code
The project is available here and can be be downloaded / cloned to your local PC with this command:
- git clone https://github.com/garyarcher36/authguidance.websample3
How to Run the Final Sample
The only difference to the Setup Instructions for the previous code sample, is to run ‘npm install’ and ‘npm start’ from new folder locations in steps 8-10:
SPA Logging Option
It is useful to be have a hidden option to look at OIDC log details for released products, in case we need to troubleshoot.
In our sample we will do this via an optional log=info query parameter, or we can specify a different level if needed: none / error / warn / debug.
‘User Loaded‘ is output whenever we call ‘Refresh Data‘, and indicates that the OIDC Client token details are being loaded from session storage.
Open Id Connect Logins
The redirect message now includes a nonce parameter, which can potentially mitigate replay attacks of previous valid login responses:
The response includes an id token, and we know that tokens we have received were issued to our SPA from our Authorization Server:
As discussed in the previous post, once this message is processed we can say the user is authenticated to our SPA.
First the token signing keys are downloaded from an Okta URL retrieved from metadata:
For the final sample we have changed the UI to get User Info directly via OIDC Client features, which is the only User Info we need in our Basic SPA:
Token renewal occurs silently behind the scenes when the Access Token is less than a minute from expiring.
I’ve added a UI Test Option to ‘expire’ a token by updating the HTML 5 storage details, so that we can invoke silent renewal on demand.
If we click it, then within a few seconds, the UserManager class will spin up an iframe and silently renew our token:
The HTTP redirect uses prompt=none, as discussed previously:
Most requests come back with a new access token, because the below Okta specific session cookie is sent on renewal requests:
We can then click Refresh Data and the main window will call the API with the new access token. That is, the End User’s session has been seamlessly extended by 30 minutes, without impacting usability.
Eventually the session cookie will expire and a login_required response will be returned during silent renewal:
If there is an error during silent iframe token renewal, our UI handles it and displays the error response on the main window:
To drill deeper into OIDC we can use log=debug and see that our access token starts with 30 minutes (1800 seconds) until expiry and ‘expiring’ + ‘expired’ timers fire every 5 seconds:
When the ‘expiring’ time counts down to zero, the token is 60 seconds from expiring, and a silent renewal is triggered:
OIDC token renewal occurs in the background rather than during End User time, which is good because we want to avoid Poor Usability if it takes 2 seconds due to a slow network.
I’m impressed with the above solution, since iframe token renewal is not easy to code reliably. We have made a good library choice in OIDC, and the result is that we get a mature tested solution for free.
We can click the Logout button to generate an Okta logout request of this form:
When processed, an HTTP debugger such as Fiddler will show that the session cookie is removed. The OIDC Client also removes tokens from storage:
Our SPA returns to a Logged Out location within our SPA. We can then click ‘Home’ to load the List View again and trigger a new API request + login.
If we didn’t implement a Logged Out view then the user would be returned to the Okta login page. However, it can be useful to ensure that our SPA flow copes with unsecured views as well as those that call APIs.
Where Are We?
All essential End User features for our SPA and API have now been coded, and the OAuth code should not need to change much in future.
The Login User Experience is limited to logins with Okta passwords. As part of a future Federation goal we will look into improving that.