Example: Web Client & Server App Authenticating with NHS Digital OAuth

Some OAuth providers enable you to reuse the authentication of an OIDC provider. If you trust that OIDC provider, have only simply requirements, then it can save your application from managing it’s own user database. The NHS Digital API Platform has a similar option, and this example walks through how to integrate with it using the standard Microsoft ASP.NET Core libraries.

This solution has a number of features (surprisingly complex)

  • Authentication is using NHS Identity
  • The authorisation is a binary allow access / deny
  • Authorisation is to both web pages on the test web app AND APIs from NHS Digital
  • Uses standard Microsoft libraries
  • We are NOT configuring a login page in the .NET project

Once the access token has been issued by NHS Digital:

  • Cookie based authentication between client and web app server
  • OAuth between web app server (Relying Party) and NHS Digital APIs
  • Access & Refresh tokens stay on the server
  • API Calls to NHS Digital must take place from your server, not client side
  • Client side code for this to work? None

The OAuth model in use is:

  • Authorisation code flow
  • Three legged model
  • Authentication is “hidden” behind authorisation call

The solution consists of:

  • ASP.NET Core 3
  • Single server page — implemented as a Razor Page for speed
  • Uses the in-built Microsoft Authentication libraries

How does this work in a project?

This is a very compact example, all the hard work is triggered on the loading of the “protected page”:

  • Startup — OAuth middleware services are configured to connect to NHS Digital API Platform
  • ProtectedPage.cshtml — Authorize attribute is used to protect the whole page and trigger an authorisation event
  • OnGet() Action — if successfully authorised, then prior to returning the page, a call to an example API is made with teh NHS Digital API Access Token returned during authorisation

Building the solution — the nitty gritty

Using Visual Studio 2019, first create the solution:

  • ASP.NET Core Web App
  • Web Application — 3.1, select No Authentication and Configure for HTTPS

Startup.cs

Configuration: Add Services

The easy part is to simply add the Microsoft Authentication and Authorization middleware into the app request processing pipeline.

Add into Configure(IApplicationBuilder app, IWebHostEnvironment env):

Although this example is not using an identity from the Microsoft framework - UseAuthentication must be included. The really important aspect that it enable is allowing the middleware to stand up the “callback” end point on the server for the OAuth flow:

  • Without this you cannot use the “authorization code” flow
  • This is the “back channel” between the authorisation server and your web app (i.e. not the client browser)
  • NHS ID authentication process to (the “authorize” leg) to hand back control to your web app (the Relying Party), via the client browser

Configuration: ConfigureServices method

To get the most out of this section, it is critical you open the sample Startup.cs file in another window: https://github.com/fromorbonia/OAuth-NHSD-API/blob/master/src/oauth-nhsd-api/Startup.cs

Configuring services code sets three services:

  • Use Cookies to store whether you are authenticated or not — between your client browser and your server. This also sets what auth is to be used when the cookies show you are not authenticated
  • Configure how the cookies behave
  • Configure OAuth

AddAuthentication() Configuration

First configure the middleware to manage the authorisation between your web client and your server. In this case it tells the service to use Cookies, just by specifying the standard Cookie scheme name (CookieAuthenticationDefaults.AuthenticationScheme).

If there is no cookie in the session, then tell the middleware how to challenge the user for authentication. In this case a custom scheme of the name NHSD is to be used.

AddCookie Configuration

Potentially there are number of options that can be set with your cookie, and by default .NET sets the ones to secure your cookie. Personally, I prefer explicitly setting security related items in the code so it is easy to validate, and clear to other coders (and more importantly new developers) just how it is secured.

Given the security of your application is at risk, you do need to fully understand the options:

AddOAuth configuration

Finally the relationship to the OAuth provider can be defined, and there is a lot to unpack here.

The configuration parameters are as follows:

ProtectedPage.cshtml

The Startup configuration simply prepares the server and middleware, but no calls have been made to authenticate / authorise. When the user navigates to the “protectedpage”, the following occurs:

  • Authorisation middleware checks for a valid cookie
  • If it doesn’t exist or expired, the middleware will trigger the OAuth Auth Code flow
  • This re-directs the client browser to the NHS Digital API authorize end point
  • Another client side redirect to NHS Identity
  • Authentication pages appear, and if successful, control is handed back to your middleware “callaback” endpoint
  • Your web app now calls the /token endpoint and is issued tokens

Creating the ProtectedPage

In this example we are using a plain Razor Page, but we are carrying out server side processing you do want to create a PageModel

Configuring ProtectedPage.cshtml.cs

To get the most out of this section, it is critical you open the sample file in another window: https://github.com/fromorbonia/OAuth-NHSD-API/blob/master/src/oauth-nhsd-api/Pages/ProtectedPage.cshtml.cs

Calling out the using statements that are relevant:

There are then only two critical areas of the code:

  • Telling .NET to protect the page
  • Calling the API with the newly issued tokens

Telling .NET to protect the page

The [Authorize] attribute is placed on the class to trigger the Microsoft authorisation framework. With the startup config provided, it uses the “NHSD” OAuth config to carry out an authorisation & authentication

Calling the API with the newly issued tokens

If the authorisation completes, then the OnGet Action gets called. You would want to encapsulate this code, but in the example I have just placed it in the page.

The first part of the method retrieves the current user (set as part of the [Authorize] processing), and uses GetTokenAsync() method to retrieve the issued Access Token. The demo also gets the Refresh Token and Token expiry time — but you don’t have to.

The second part uses HttpRequestMessage to make the actual API call:

  • Often the API root path for OAuth and the APIs will happen to be the same
  • The access token is placed in a Bearer type Authorization header
  • Call is made

Remaining code — used for the demo

There are three public properties (ResResponse, ResContent and SessionExpires) added to pass the values of the responses to the page being rendered.

A private variable (_configuration) is used to expose an injected Configuration service to access application settings and secrets

There is nothing at all added to ProtectedPage.cshtml that impacts the functionality, the HTML is just to display the results of the call

Configuring NHS Digital API Management Portal

For this to work, you need to have an application configured in the NHS Digital Developer Account. You need this to provide a Client ID and Secret for you to call the service.

You can follow the tutorial here to create the app:

The only extra instructions are that when you are configuring your App:

  • Also activate the “Personal Demographics Service (Integration Testing)” API
  • The callback URL has to be the one you defined: https://<Your web server address/MyWebServerCallBack, and (in this context) having a local host call back works

Put the Client ID & Secret into your secrets store and run the web app…

Detailed Security Considerations

This section isn’t a full analysis, really just looking at one aspect of this solution. Aspects that bothered me with this default Microsoft solution were (a) how strong is using cookie authentication, alongside (b) where does the session state get stored…

(a) —on my todo list to carry out some research to make further comment, it is in widespread use.

(b) — that is much more interesting, and frustratingly hard to find out just basic details. After a bit of digging it appears that the sensitive server side Access and Refresh tokens are encrypted and stored in the ASP.NET session cookie…

Part of the point in having the three legged auth is that the /token endpoint is called from a relying party that is also a “confidential client”. This is to ensure the tokens stay on the confidential client and are not distributed to a “public client”…

Storing the session state on each client, rather than on your web server infrastructure is brilliant for stateless server side applications that support a significant number of concurrent users. However:

  • How sensitive are you to having your access tokens encrypted on a public client? With good encryption the end user won’t be able to decrypt it
  • Size of the cookie (and associated header) could grow quickly in size causing multiple issues

If this is an issue, and you don’t want to switch to using a OAuth between your client and your server (introducing a second OAuth segment), you can consider using a Ticket Store in the Cookie configuration. This moves the session state server side, but you then have the associated state problems when running across a load-balanced solution.

Main Links & Further Reading

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Aubyn Crawford

I have worked as an independent IT Consultant for 21 years. I excel at bringing together and architecting complex solutions, and delivering them.