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.


Tutorials

You can learn how to use this security pattern with our tutorials written in:

Bear in mind that the tutorial only teaches you the basic flow. You'll also need to read the detailed integration instructions below to understand how to handle error scenarios.


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 - second generation All APIs int.api.service.nhs.uk/oauth2-mock Not applicable
Integration test Simulated sign-in - first generation - deprecated 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 register 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. Best practice is to register 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 'Environment access' on my developer account.
  4. Select 'Add new application'.

  5. Enter the details of your application including application owner and application name to create your new application.

  6. Select 'View your new application' to check or edit your application details.
  7. Click the 'Edit' button to make a note of the API key. If you are editing the security details for production applications, follow the online instructions to set up mobile authentication. 
  8. Click the 'Add APIs' button to add the API you want to use.

For the Hello World (Sandbox) example, you need to select the API "Hello World API - User Restricted (Sandbox)".


Step 3: Generate a key pair

You need to generate a private/public key pair, which is used to create a client_assertion later in the process, for each application you created in Step 2 to access testing or production environments. It must be a 4096-bit RSA key pair.

Note that if you generate your own JWKS file, you must use the RS512 algorithm to do this.

Decide on your 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 multiple applications to test across multiple test environments, you need a different KID and key pair for each environment.

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.

For development and integration test environments only, you might find it easiest to use an external key generator to create a private-public key pair, and a JWKS file. Do not use this for a production environment.

For production environments (or test environments), generating your own public-private key locally is much more trustworthy.

Generate a private/public key pair using an external key generator - for test environments only

There are several external key generators available on the internet, and while we cannot endorse any one in particular, we know people have had success with https://mkjwk.org/.

To use it, enter:

Key Size: 4096
Key Use: Signature
Algorithm: RS512
Key ID:   YOUR_KID
Show X.509: Yes

This produces:

  • "Public Key" - your JWKS file for uploading
  • "Private Key (X.509 PEM Format)" - your private key in PEM format
  • "Public Key (X.509 PEM Format)" - your public key in PEM format

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

Go to Step 4.

Generate your own private/public key pair - for production or test environments

On Windows, the easiest way to get the BASH shell tools to do this is to install Git For Windows.
On Linux and Mac OS, the BASH shell comes as standard.

Open a BASH shell command prompt and define your KID:

KID=YOUR_KID

Then run both of the following commands:

  1. openssl genrsa -out $KID.pem 4096
  2. openssl rsa -in $KID.pem -pubout -outform PEM -out $KID.pem.pub

These commands create the following files:

  • YOUR_KID.pem - your private key in PEM format
  • YOUR_KID.key.pub - your public key in PEM format

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

If this is a key pair for a production application, and you want us to host your public key, go to Step 4.

If this is a key pair for development or integration testing environments, or a production environment key you want to host yourself, you also need to create a JWKS file to upload.

To do this, first get the "modulus" of your private key, by entering the following BASH shell commands:

MODULUS=$(
    openssl rsa -pubin -in $KID.pem.pub -noout -modulus `# Print modulus of public key` \
    | cut -d '=' -f2                                    `# Extract modulus value from output` \
    | xxd -r -p                                         `# Convert from string to bytes` \
    | openssl base64 -A                                 `# Base64 encode without wrapping lines` \
    | sed 's|+|-|g; s|/|_|g; s|=||g'                    `# URL encode as JWK standard requires`
)

Next, build your JWKS file (using the RS512 algorithm) from your KID and public key modulus by entering the following BASH shell commands:

echo '{
  "keys": [
    {
      "kty": "RSA",
      "n": "'"$MODULUS"'",
      "e": "AQAB",
      "alg": "RS512",
      "kid": "'"$KID"'",
      "use": "sig"
    }
  ]
}' > $KID.json

This creates the JWKS file YOUR_KID.json for uploading in Step 4.


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, for applications in development or integration test environments:

  1. Create a JWKS endpoint to publicly host your public key and note the URL.
  2. Sign in to your developer account.
  3. Select 'My applications and teams', 'My applications' and then 'Manage your applications'.
  4. Select the application you want to add your JWKS endpoint to.
  5. Edit the public key URL
  6. Enter the URL of your JWKS endpoint and click Save.

If this public key is for a production application, contact us and tell us:

  • your application ID
  • the public key URL you want to add, or update

Ask us to host your public key

For applications in development or integration test environments:

  1. Sign in to your developer account.
  2. Select 'My applications and teams', 'My applications' and then 'Manage your applications'.
  3. Select the application you want to add your JWKS public key to.
  4. Edit the public key URL.
  5. Choose the JWKS file in JSON format for your public key and click Upload.
  6. Once it's confirmed as a valid public key, click Save.

We use this public key to create a JWKS endpoint to host your public key and link it to your application in the development or integration environment.

For production applications, contact us and make sure you tell us:

  • your application’s App ID, from step 2
  • your KID, from step 3
  • your public key, from step 3, as an attachment in PEM format
  • 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 production.

In the future, we hope to make this process more self-service for production applications. 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.

The ID token has a lifetime of 1 hours, after 1 hour the user must re-authenticate. We strongly recommend to exchange the ID token for our access and refresh tokens as soon as possible. 

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, which must be 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#.

For the Python example, PyJWT requires the installation of the crypto extra in order to use RSA keys. To install this:

python -m pip install PyJWT[crypto]

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 in your call:

Parameter Description
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 As per Section 4.5 of RFC6749, the grant type to receive an access token should be 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 HTTP status 200 and a normal OAuth 2.0 response from the token endpoint. This response contains the following parameters:

Parameters Description
access_token The access token issued by the OAuth 2.0 authorization server which can be used to call our user-restricted endpoints
expires_in The time after which the access token expires, in seconds
issued_token_type urn:ietf:params:oauth:token-type:access_token
token_type Bearer
refresh_token A token for refreshing the access token once it has expired (see step 10 below)
refresh_token_expires_in The time in seconds, after which the refresh token expires
refresh_count The number of times the token has been refreshed so far

Here’s an example:

{
   "access_token":"Sr5PGv19wTEHJdDr2wx2f7IGd0cw",
   "expires_in":"599",
   "issued_token_type":"urn:ietf:params:oauth:token-type:access_token",
   "refresh_count":"0",
   "refresh_token":"7qvwCqqUUAmzMjRbQyrhdddwBQUJ9vmt",
   "refresh_token_expires_in":"3599",
   "token_type":"Bearer"
}

Error scenarios

If there are any issues with your call to our token endpoint, we return an error response, as follows:

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
Client assertion type is missing or invalid 400 (Bad Request) invalid_request Missing or invalid client_assertion_type - must be 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
Subject token type is missing or invalid 400 (Bad Request) invalid_request Missing or invalid subject_token_type - must be 'urn:ietf:params:oauth:token-type:id_token'
Client assertion (signed JWT) is missing 400 (Bad Request) invalid_request Missing client_assertion
Client assertion (signed JWT) is malformed 400 (Bad Request) invalid_request Malformed JWT in client_assertion
Subject token is missing 400 (Bad Request) invalid_request Missing subject_token
Subject token is invalid 400 (Bad Request) invalid_request subject_token is invalid
kid header is missing in client_assertion 400 (Bad Request) invalid_request Missing 'kid' header in client_assertion JWT
kid header is invalid in client_assertion 401 (Unauthorized) invalid_request Invalid 'kid' header in client_assertion JWT - no matching public key
kid header is missing in subject_token 400 (Bad Request) invalid_request

Missing 'kid' header in subject_token JWT

kid header is invalid in subject_token 401 (Unauthorized) invalid_request Invalid 'kid' header in subject_token JWT - no matching public key
typ header is missing or invalid in client_assertion 400 (Bad Request) invalid_request Invalid 'typ' header in client_assertion JWT - must be 'JWT'
typ header is missing or invalid in subject_token 400 (Bad Request) invalid_request Invalid 'typ' header in subject_token JWT - must be 'JWT'
alg header is missing in client_assertion 400 (Bad Request) invalid_request Missing 'alg' header in client_assertion JWT
alg header is invalid in client_assertion 400 (Bad Request) invalid_request Invalid 'alg' header in client_assertion JWT - unsupported JWT algorithm - must be 'RS512'
alg header is missing in subject_token 400 (Bad Request) invalid_request Missing 'alg' header in subject_token JWT
sub and iss claims match but are not a valid API Key in client_assertion 401 (Unauthorized) invalid_request Invalid 'iss'/'sub' claims in client_assertion JWT
sub and iss claims don't match or are missing in client_assertion 400 (Bad Request) invalid_request

Missing or non-matching 'iss'/'sub' claims in client_assertion JWT

iss claim is missing in subject token 400 (Bad Request) invalid_request

Missing 'iss' claim in subject_token JWT

jti claim is missing in client_assertion 400 (Bad Request) invalid_request Missing 'jti' claim in client_assertion JWT
jti claim has been reused in client_assertion 400 (Bad Request) invalid_request Non-unique 'jti' claim in client_assertion JWT
jti claim is invalid type in client_assertion 400 (Bad Request) invalid_request

Invalid 'jti' claim in client_assertion JWT - must be a unique string value such as a GUID

aud claim is missing or invalid in client_assertion 401 (Unauthorized) invalid_request Missing or invalid 'aud' claim in client_assertion JWT
aud claim is missing in subject_token 400 (Bad Request) invalid_request

Missing aud claim in subject_token

exp claim is missing in client_assertion 400 (Bad Request) invalid_request Missing 'exp' claim in client_assertion JWT
exp claim is in the past in client_assertion 400 (Bad Request) invalid_request Invalid 'exp' claim in client_assertion JWT - JWT has expired
exp claim is more than 5 minutes in the future in client_assertion 400 (Bad Request)  invalid_request Invalid 'exp' claim in client_assertion JWT - more than 5 minutes in future
exp claim is invalid type in client_assertion 400 (Bad Request) invalid_request

Invalid 'exp' claim in client_assertion JWT - must be an integer

exp claim missing in subject_token 400 (Bad Request) invalid_request Missing 'exp' claim in subject_token JWT
exp claim is in the past in subject_token 400 (Bad Request) invalid_request Invalid 'exp' claim in subject_token JWT - JWT has expired
exp claim is invalid type in subject_token 400 (Bad Request) invalid_request

Invalid 'exp' claim in subject_token JWT - must be an integer

JWT signature is invalid 401 (Unauthorised) public_key error JWT signature verification failed
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. To 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 when your access token expires, see refresh your access 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

Your access token from step 7 above expires after 10 minutes and must be refreshed to avoid user re-authentication (see step 5 above).

If your access token has expired, when you call a user-restricted API, we return the following error:

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

Each access token has a corresponding refresh token. To refresh the access token, submit the expired token’s corresponding refresh token to our token endpoint using grant_type of refresh_token. We return a new pair of access token and it's corresponding refresh token without re-authenticating the user.

You need to include the following form parameters in your request to the token endpoint:

Parameters Description
client_id The API Key (also known as the Client ID) of your application
client_secret The secret assigned to your application’s API Key
grant_type As per the OAuth standard, the grant type to refresh your access token should be refresh_token
refresh_token The refresh token issued by the OAuth 2.0 authorization server which can be used to refresh the access token

If you refresh an access token before it expires, the new access token invalidates the original access token immediately. 

You can continue to refresh access tokens for up to 1 hour. After 1 hour, you must repeat step 5 above.

Example request

curl -X POST -H "content-type: application/x-www-form-urlencoded" --data \

"client_secret=[YOUR-SECRET]\

&client_id=[YOUR-API-KEY]\

&grant_type=refresh_token\

&refresh_token=[REFRESH_TOKEN]" \

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

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

Example response

HTTP/1.1 200 OK Content-Type: application/json
{
   "access_token":"xjPOKAmxlLXQcHkRkBf37AiaGyEx",
   "expires_in":"599",
   "refresh_token":"A6dpFV8F1yjsca4zPr5GDO0n7raSB6TQ",
   "refresh_token_expires_in":"3599",
   "refresh_count":"1",
   "token_type":"Bearer"
}

Error scenarios

If there are any issues with your call to our token endpoint, in addition to the errors mentioned in step 7, we return the following refresh token specific errors: 

Error scenario HTTP status Error code Error message
Client secret is missing 401 (Unauthorized) invalid_request client_secret is missing
Client secret is invalid 401 (Unauthorized) invalid_client client_id or client_secret is invalid
Client ID (API key) is missing 401 (Unauthorized) invalid_request client_id is missing
Client ID (API key) is invalid 401 (Unauthorized) invalid_client client_id or client_secret is invalid
Refresh token is missing 400 (Bad Request) invalid_request refresh_token is missing
Refresh token is invalid 401 (Unauthorized) invalid_grant refresh_token is invalid
Refresh token has already been used 401 (Unauthorized) invalid_grant refresh_token is invalid
Access token refresh period has expired 401 (Unauthorized) invalid_grant access token refresh period has expired

Step 11: Request a new access token from us

You can continue to request new access_tokens for up to 1 hour.

After that, calls to our token endpoint returns the following error:

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

If this happens, you must send the user back through the full authorisation process from step 5 above.

If you have any concerns about the session length regarding your use case then then contact us about  about it and we will work with you to make it a smooth as possible user experience.


Revoking authority

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

Last edited: 9 April 2024 7:28 am