In our last post we provided an Improved SPA Overview. We will look at the key technical points below.
Unobtrusive OAuth Code
Our code layout has been updated to look as follows, since the important UI code is our application logic, which we want to keep clean and evolve often based on business requirements.
Plumbing code related to OAuth or error handling will be written once, and then will not change. So we’ll move it to a subfolder and can forget about it once it is finished.
UI Location and Navigation
In a Single Page Application the behavior should be roughly as follows, and we will see that OAuth code can integrate nicely with these concerns:
- Download the web page when the user first accesses the app
- Use REST based URLs for locations within the Web UI
- Updating a URL raises a router event which then selects the view
- A view gets data via fast Ajax requests and updates the DOM
You can use either path or hash based routing in your SPA, and I chose to use hash based routing because it was simplest to implement:
- I want the Server Side of my Code Sample to have zero logic
- SEO is not a factor I care about, since the UI is behind a ‘Login Wall’
A Real World SPA would typically use a framework such as Angular or React, in which case you will have more powerful options for areas like Routing.
UI Data / Navigation Changes
Our sample shows how the implicit flow deals elegantly with SPA locations across login redirects. Consider the following change to the hash location, in listView.js, when a startup is clicked in the list view.
The hash change event is handled in the main app.js file, and executeView acts as a router that works out which view to load:
We use the OIDC Client library in authenticator.js to store application state during an OAuth redirect and then maintain the user’s UI location upon return from login:
API Claims Caching
Our Claims Middleware has been extended to cache the results of Introspection. The ClaimsHandler class represents an outline of processing:
Lower level details are deferred to the Authenticator class, which uses the OpenId-Client library to take care of these plumbing details:
- Metadata Lookup to get Endpoints
- Token Introspection to read Token Claims
- An API call to read Central User Data
- A placeholder that could read Product Specific User Data
The ClaimsCache class is a simple wrapper around the NodeJs MemoryCache, which supports caching an item until the access token’s expiry time:
API Claims Caching and Reliability
There are 2 important reliability concerns that you will need to cover in this type of solution:
|Thread Safe Memory Cache||UTC Based Timestamps|
If you are working on a .Net based API then I would recommend using the Identity Server Implementation or basing your solution on it.
UI User Info Lookup
Our UI gets its User Info by calling its API, and this data could contain whatever is needed by our SPA:
This is a little contrived in our case, since our Code Sample only needs to display who is logged in:
Error Handling Classes
In code we have added Error Entities in both the API and UI – and constructors ensure that all fields have good defaults:
A higher level ErrorHandler class is used by the rest of the application. It is responsible for creating error instances and populating them with details such as those from OAuth error responses:
The ErrorHandler class deals with error logic. The API error handler logs technical details server side, then returns a less detailed error to the UI:
Where Are We?
Our Code Sample has been updated to handle Claims in both the UI and API. Business logic is cleanly separated from plumbing code and it is easy to extend either.