Skip to main content

User-restricted RESTful APIs - NHS login separate authentication and authorisation

Learn how to integrate your software with our user-restricted RESTful APIs - using our NHS login separate authentication and authorisation pattern.

Overview

This page explains how to integrate your software with our user-restricted RESTful APIs.

In particular, it describes the NHS login separate authentication and authorisation pattern, which uses our OAuth 2.0 authorisation server. It also describes the signed JWT authentication and authorisation pattern which is used for application authentication.

For a full list of available patterns, see Security and authorisation.


When to use this pattern

Use this pattern when:

  • you want to access a user-restricted RESTful API

  • you want to separate authentication from authorisation

  • the end user is registered at a GP practice in England, or is receiving NHS services in England

  • you need the end user's identity information


How this pattern works

In this pattern, authentication and authorisation are done separately. You might authenticate the user when they sign in but only get authorisation to call the API if and when you need it. You do authentication directly with NHS login and then separately do authorisation with our OAuth2.0 authorisation service. You need to register your application separately with NHS login and with the API Platform.

The end user authenticates by entering their NHS login email address and password. The user then needs to provide a mobile phone number to receive a one time password (OTP) via a text message. The user needs to enter this OTP when prompted and press continue.

The end user has now verified the ownership of an email address and mobile phone number. This means they have an NHS login with the lowest level of identity verification. For details, see levels of verification.

The following diagram illustrates the pattern:

include authz
access token
include authz...
authenticate user
authenticate user
get authn
access token
and ID token
get authn...
Calling Application
Calling Applicati...
User-Restricted
API
User-Restricted...
Authorization Server
(OAuth 2.0)
Authorization Ser...
exchange
id token for
authz access
token
exchange...
NHS login
(Open ID Connect)
NHS login...
End user
End user
Viewer does not support full SVG 1.1 Context diagram of separate authentication with NHS login and authorisation with OAuth 2.0


The following sequence diagram shows how the various components interact:

Calling Application
Calling Applic...
Authorization Server
Authorization...
NHS login
NHS login
User-Restricted API
User-Restricte...
End User / Browser
End User /...
do something
do something
launch application
launch application
redirect to
authentication
redirect to...
display sign in page (or equivalent)
display sign in page (or equivalent)
redirect to authentication
redirect to authentication
redirect back to calling application
(with authorisation code)
redirect back to calling application...
sign in
sign in
return access token
return access token
exchange token
(/oauth2/token)
exchange token...
redirect back to
calling application
redirect back to...
display home page
display home page
return access token
and ID token
return access token...
get tokens
(/oauth2/token)
get tokens...
call user-restricted API
(include access token)
call user-re...
Viewer does not support full SVG 1.1 Sequence diagram of separate authentication with NHS login and authorisation with OAuth 2.0


In words:

  1. The calling application forwards the user's browser to the NHS login authentication endpoint.

  2. The user signs in to their NHS login account (using a username and password, or other method).

  3. NHS login redirects the user's browser back to the calling application, with an authorisation code.

  4. The calling application calls the NHS login token endpoint, with the authorisation code, and receives an access token and an ID token in return.

  5. Time passes, until the user needs to access a user-restricted API.

  6. The calling application calls our OAuth2.0 token endpoint (/oauth/token), passing the ID token, and receives an access token (a token exchange).

  7. The calling application calls the user-restricted API, including the access token.


Detailed integration instructions

The following diagram shows the high level integration stages with the API platform and the sections below it explain in detail how to use this security pattern.

Set up your application
Set up your appli...
Authorise your application
Authorise your ap...
Interact with our user-restricted APIs
Interact with our...
Phase 1
Phase 1
Phase 2
Phase 2
Phase 3
Phase 3
Viewer does not support full SVG 1.1 Phase 1 set up your application, phase 2 authorise your application, phase 3 interact with our user-restricted APIs

Environments and testing

As well as production, we have a number of test environments. Each environment is paired with a suitable NHS login environment. In the steps below, make sure you use the appropriate URL base path:

Environment Sign-in method Availability URL base path Paired NHS login environment 
Sandbox Simulated sign-in Hello World API only (all other sandbox APIs are open access) sandbox.api.service.nhs.uk/oauth2 Not applicable
Development Simulated sign-in Limited to specific APIs - check your API specification dev.api.service.nhs.uk/oauth2-no-smartcard Not applicable
Development NHS login username and password Limited to specific APIs - check your API specification dev.api.service.nhs.uk/oauth2 Sandpit
Integration test Simulated sign-in All APIs int.api.service.nhs.uk/oauth2-no-smartcard Not applicable
Integration test NHS login username and password All APIs int.api.service.nhs.uk/oauth2 Integration 
Production NHS login username and password All APIs api.service.nhs.uk/oauth2 Live production

For more information on testing, see Testing APIs.


Phase 1: Set up your application

This section explains the detailed steps to set up your application before you can initiate authorisation. The steps involved are:

  • register your application with NHS login
  • register your application on the API platform
  • generate a key pair
  • register your public key 

Step 1: Register your application with NHS login

To use this pattern you need to register your application with NHS login directly. NHS login provides a number of ways for patients to authenticate their identity when accessing national clinical information systems.

Note:  There are a number of distinct stages and this step is the setup stage. In a later stage, this configuration allows you to obtain an ID token. The ID token, in turn, provides an access token for calling the API and retrieve the data.


Step 2: Register your application on the API platform

To use this pattern, you need to create a new application on the API platform. This allows you to select and manage which APIs the application can access.

You need a separate application for your production environment, and best practice is to create one application for each of the test environments you want to access - development, integration test, or (for Hello World API only) sandbox:

  1. If you do not already have one, create a developer account.

  2. Navigate to my developer account and sign in.

  3. Select 'My applications'.

  4. Select '+ NEW APP'.

  5. Enter details for your application.

  6. In the 'APIs' section, find the testing API you want to use and activate it by clicking the ‘Enable’ button under the Actions column.

  7. Enter the callback URL for your application.

  8. Select 'CREATE' to create the application.

  9. Make a note of the App ID and API Key (also known as the Client ID).


Step 3: Generate a key pair

Generate a private and public key pair which is used to create a client_assertion later in the process, for each application you created in step 2..  It must be a 512-byte RSA version 2 key pair.

For example, to do this on UNIX (Linux, MacOS), run both of the following commands:

  1. $ ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS512.key
  2. $ openssl rsa -in jwtRS512.key -pubout -outform PEM -out jwtRS512.key.pub

The simplest way to do this on Windows, is to check that you have the OpenSSH client installed, which means you also have ssh-keygen installed. If not, go to 'Settings' and navigate to Apps > Apps and Features > Optional Features and install the OpenSSH client.

Next, open a command prompt and run both of the following commands:

1. > ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS512
2. > ssh-keygen -f jwtRS512.pub -e -m pem > "./jwtRS512.key.pub"

These UNIX and Windows commands create the following files:

  • jwtRS512.key (UNIX) or jwtRS512 (Windows) - is your private key in PEM format
  • jwtRS512.pub (Windows only) - is your public key in OpenSSH authorized_keys format - which is not used
  • jwtRS512.key.pub - is your public key in PEM format

Important - always keep your private key private. Do not send it to us!

Decide on a Key Identifier (KID) - a unique name to identify the key pair in use. The KID will be used to refer to the key pair when constructing and posting the JWT. We recommend:

  • test-1 for testing
  • prod-1 for production use

If you create subsequent key pairs for key rotation, number them sequentially, for example test-2test-3 and so on. Do not re-use a KID.


Step 4: Register your public key

We use your public key to verify your client_assertion later in the process.

There are two ways to do this - either host your own public key, or ask us to host it for you.

Host your own public key

To do this:

  1. Create a JWKS endpoint to publicly host your public key and note the URL.
  2. Navigate to my developer account and sign in.
  3. Select 'My applications'.
  4. Select the application you want to add your JWKS endpoint to.
  5. Enter the URL of your JWKS endpoint and click Save.

Ask us to host your public key

To do this, contact us and make sure you tell us:

  • the environment you want to access - development, integration test, production, or (for Hello World API only) sandbox
  • your application’s App ID, from step 2 
  • your KID, from step 3 
  • your public key, from step 3, as an attachment 
  • the APIs you want to use

We use this information to create a JWKS endpoint to host your public key and link it to your application.

In the future we hope to make this process self-service. You can track progress or vote for this feature on our interactive product backlog.


Phase 2: Authorise your application

This section explains the steps to get your application authorised before calling the user-restricted API. The steps involved are:

  • authorise the user with NHS login
  • generate a client assertion
  • exchange NHS login ID token for access token
  • store our access token for later use

Step 5: Authenticate the user with NHS login

You need to authenticate the user with NHS login. Successful authentication results in an ID token being issued to the callback endpoint that you registered with NHS login.

Your software needs to follow a standard OIDC authorisation code flow with NHS login. OIDC clients Initiate the NHS login authorisation sequence from the browser by calling the NHS login authorize endpoint. Once the user authentication is successful, your web server should call the NHS login token end point and receive a number of tokens including the ID Token.

You need the ID Token in  Step 7.


Step 6: Generate a client assertion

Before you can call a user-restricted API, you first need to generate a client assertion. This happens at runtime, so you need to code it into your application.

A client assertion is a JSON Web Token (JWT) that consists of three parts: a header, a payload and a signature. The header specifies the authentication method and token type. The payload contains data (detailed below) and the signature is used to verify the token itself.

We strongly recommend that you use a library to generate your JWT, as this can be a complicated process to perform by hand.

Header

The JWT header includes the following fields:

Field Description Type
alg The algorithm used to sign the JWT. In this case, RS512. string
typ The token type - JWT. string
kid

The Key Identifier (KID) used to select the public key to use to verify the signature of the JWT, for example test-1. If you have multiple public/private key pairs, this will be used to select the appropriate public key.

string

Example

{
  "alg": "RS512",
  "typ": "JWT",
  "kid": "test-1"
}

Payload

The JWT payload includes the following fields:

Field Description Type             
iss The issuer of the JWT. Set this to your API Key. string
sub The subject of the JWT. Also set this to your API Key. string
aud The audience of the JWT. Set this to the URI of the token endpoint you are calling, for example  https://api.service.nhs.uk/oauth2/token for our production environment. string
jti A unique identifier for the JWT, used to prevent replay attacks. We recommend a randomly-generated GUID. string
exp Expiry time of the JWT, expressed as a Numeric Time value - the number of seconds since epoch (for example, a UNIX timestamp). Must not be more than 5 minutes after the time of creation of the JWT. number  

Example

{
  "iss": "<test-app-api-key>",
  "sub": "<test-app-api-key>",
  "aud": "https://api.service.nhs.uk/oauth2/token",
  "jti": "<unique-per-request-id>",
  "exp": <current-time-plus-5mins-from-jwt-creation>
}

Signature

The JWT signature consists of the contents of the header and payload, signed with your private key. We recommend you use a library to generate this.

Assembling the JWT

The JWT consists of:

  • the header, base64 encoded
  • a period separator
  • the payload, base64 encoded
  • a period separator
  • the signature, base64 encoded

Examples

The following code snippets show how to generate and sign a JWT in Python and C#

import uuid

from time import time

import jwt  # https://github.com/jpadilla/pyjwt



with open("jwtRS512.key", "r") as f:

  private_key = f.read()



claims = {

  "sub": "<API_KEY>",

  "iss": "<API_KEY>",

  "jti": str(uuid.uuid4()),

  "aud": "https://api.service.nhs.uk/oauth2/token",

  "exp": int(time()) + 300, # 5mins in the future

}



additional_headers = {"kid": "test-1"}



j = jwt.encode(

  claims, private_key, algorithm="RS512", headers=additional_headers

)
using System; using System.Collections.Generic; 

using System.IdentityModel.Tokens.Jwt; 

using System.Security.Claims; 

using System.Security.Cryptography.X509Certificates; 

using IdentityModel; 

using Microsoft.IdentityModel.Tokens;



public class JwtHandler

{    

     private readonly X509Certificate2 _cert;

     private readonly string _audience;

     private readonly string _clientId;

     private readonly string _kid;



     public JwtHandler(string pfxCertPath, string audience, string clientId, string kid)

     {

         _audience = audience;

         _clientId = clientId;

         _kid = kid;

         _cert = new X509Certificate2(pfxCertPath);

     }



     public string generateJWT(int expInMinutes = 1)

     {

         var now = DateTime.UtcNow;



         var token = new JwtSecurityToken(

             _clientId,

             _audience,

             new List<Claim>

             {

                 new ("jti", Guid.NewGuid().ToString()),

                 new (JwtClaimTypes.Subject, _clientId),

             },

             now,

             now.AddMinutes(expInMinutes),

             new SigningCredentials(

                 new X509SecurityKey(_cert, _kid),

                 SecurityAlgorithms.RsaSha512

             )

         );

         var tokenHandler = new JwtSecurityTokenHandler();



         return tokenHandler.WriteToken(token);

     }

}

Step 7: Exchange NHS login ID token for access token

Once you integrate with NHS login and successfully authenticate the user, you receive an ID token. Call our token endpoint to exchange the ID token for an access token. This call is an HTTP POST to the following endpoint:

https://api.service.nhs.uk/oauth2/token

Note: the above URL is for our production environment. For other environments, see Environments and testing above.

You need to include the following form parameters:

  • subject_token = ID token received from NHS login in step 5. 

  • client_assertion= A JWT token, which is created to prove that your server is a legitimate consumer and contains the application (client_id) as a claim.

  • subject_token_type= urn:ietf:params:oauth:token-type:id_token

  • client_assertion_type= urn:ietf:params:oauth:client-assertion-type:jwt-bearer

  • grant_type= urn:ietf:params:oauth:grant-type:token-exchange

Here is a complete example, as a CURL command:

curl --location --request POST 'https://api.service.nhs.uk/oauth2/token'\
--header 'Content-Type: application/x-www-form-urlencoded'\
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange'\
--data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:id_token'\
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer'\
--data-urlencode 'subject_token={ID token received from NHS login in step 5}\
--data-urlencode 'client_assertion={jwt token}

If the request is valid, the OAuth 2.0 authorisation server responds with a 200 and a normal OAuth 2.0 response from the token endpoint. This response contains the following parameters:

  • access_token= the access token issued by the OAuth 2.0 authorisation server which can be used to call our user-restricted endpoints

  • expires_in= the time after which the access token will expire, in seconds

  • issued_token_type= urn:ietf:params:oauth:token-type:access_token

  • token_type = Bearer

Error scenarios

If there are any issues with your call to our token endpoint, we return once of the following token exchange specific errors:

Error Scenario HTTP status Error code Error message
Grant type is missing 400 (Bad Request) invalid_request grant_type is missing
Grant type is invalid 400 (Bad Request) unsupported_grant_type grant_type is invalid
Grant type is invalid but is supported 400 (Bad Request) invalid_grant_type grant_type is invalid
Missing or invalid Subject Token Type 400 (Bad Request) invalid_request missing or invalid subject_token_type - must be ‘urn:ietf:params:oauth:token-type:id_token’
Missing exp claim 400 (Bad Request) invalid_request Missing exp claim in subject_token
Missing or invalid iss claim 400 (Bad Request) invalid_request Missing or non-matching iss/sub claims in subject_token
Missing aud claim 400 (Bad Request) invalid_request Missing aud claim in subject_token
Public key not set up 403 (Forbidden) public_key error You need to register a public key to use this authentication method - please contact support to configure
Public key misconfigured 403 (Forbidden) public_key error The JWKS endpoint, for your client_assertion can not be reached

Step 8: Store your access token for later use

Your access token lasts for 10 minutes and you can use it multiple times. If you'll be making more than one API call for this user, store your access token securely for later use.

This reduces the load on our authorisation server and also reduces the chance of your application hitting its rate limit.

For details on what to do if your access token has expired, see refresh token below.


Phase 3: Interact with our user-restricted APIs

This section explains the detailed activities that you need to perform to call a user-restricted API. The activities involved are:

  • call a user-restricted API
  • refresh our access token
  • request a new access token from us

Step 9: Call a user-restricted API

To call our user-restricted APIs, you need to include the following header in your call:

  • Authorization = Bearer <your access token from step 7>

Here's an example, using a CURL command:

curl -X GET https://sandbox.api.service.nhs.uk/hello-world/hello/user\
-H "Authorization: Bearer [your access token from step 7]"\

Note: the URL in the above example is for our sandbox environment. For other environments, see Environments and testing above.

All being well, you receive an appropriate response from the API, for example:

HTTP Status: 200

{
  "message": "Hello User!"
}

Error scenarios

If there is an issue with your access token, we return one of the following error responses:

HTTP status Code Description
401 (Unauthorized) invalid_credentials Access token has expired
401 (Unauthorized) invalid_credentials Access token is invalid
401 (Unauthorized) invalid_credentials Access token is missing

For detailed error conditions, see the relevant API specification in our API catalogue.


Step 10: Refresh your access token

We currently do not support refresh tokens for the separate authentication and authorisation model due to limitations. However, this is a feature we intend to add in the future and we will update this section once completed.


Step 11: Request a new access token from us

Access tokens have a lifetime of 10 minutes, so when that expires the ID token has to be exchanged for a new access token, see step 7 above. 

The NHS login ID token is only valid for an hour from issue.


Revoking authority

For details on how to revoke an access token, please contact us.

Last edited: 9 May 2022 1:31 pm