Skip to main content
Creating a new NHS England: Health Education England, NHS Digital and NHS England have merged. More about the merger.

User-restricted RESTful APIs - NHS Care Identity Service 2 separate authentication and authorisation

Learn how to integrate your software with our user-restricted RESTful APIs - using our NHS Care Identity Service 2 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 CIS2 Authentication 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:

  • accessing a user-restricted RESTful API
  • the end user is a healthcare worker
  • you want to separate authentication from authorisation
  • you need the healthcare worker's identity information

In particular, this pattern is appropriate when building GP software.


How this pattern works

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

The healthcare worker authenticates with either an NHS smartcard or a more modern alternative. To use smartcards, you need to be connected to the Health and Social Care Network (HSCN).

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 CIS2
(Open ID Connect)
NHS CIS2...
End user
End user
Viewer does not support full SVG 1.1 Context diagram of separate authentication with CIS2 and authorisation with OAuth 2.0


The following sequence diagram shows how the various components interact:

Calling Application
Calling Applic...
Authorization Server
Authorization...
NHS CIS2
NHS CIS2
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-res...
Viewer does not support full SVG 1.1 Sequence diagram of separate authentication with CIS2 and authorisation with OAuth 2.0


In words:

  1. The healthcare worker launches the calling application.
  2. The calling application forwards the healthcare worker's browser to the NHS CIS2 Authentication endpoint.
  3. The healthcare worker authenticates with their preferred mechanism (this could be using their face, fingerprint, security key or a smartcard and PIN).
  4. NHS CIS2 Authentication redirects the healthcare worker's browser back to the calling application, with an authorisation code.
  5. The calling application calls the NHS CIS2 Authentication token endpoint, with the authorisation code, and receives an access token and an ID token in return.
  6. Time passes, until the healthcare worker needs to access a user-restricted API.
  7. The calling application calls our OAuth2.0 token endpoint (/oauth2/token), passing the ID token, and receives an access token (a token exchange).
  8. The calling application calls the user-restricted API, including the access token.

Using this pattern with CIS

If you are already using our original Care Identity Service (CIS) in your application, see Using CIS2 with CIS for API access.


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 phases with API platform and the steps 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 CIS2 Authentication environment. In the steps below, make sure you use the appropriate URL base path:

Environment Sign-in method Availability URL base path

Paired NHS CIS2 Authentication environment  

Sandbox Simulated sign-in - no smartcard needed Hello World API only (all other sandbox APIs are open-access) sandbox.api.service.nhs.uk/oauth2 Not applicable
Integration test Simulated sign-in - no smartcard needed - second generation All APIs int.api.service.nhs.uk/oauth2-mock Not applicable
Integration test Simulated sign-in - no smartcard needed - first generation - deprecated All APIs int.api.service.nhs.uk/oauth2-no-smartcard Not applicable
Integration test Any of the NHS CIS2 Authentication mechanisms All APIs int.api.service.nhs.uk/oauth2 Integration (INT)
Production Any of the NHS CIS2 Authentication mechanisms All APIs api.service.nhs.uk/oauth2 Live

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 CIS2 Authentication
  • register your application on the API platform
  • generate a key pair
  • register your public key 

Step 1: Register your application with NHS CIS2 Authentication

To use this pattern you need to register your application with NHS CIS2 Authentication directly. NHS CIS2 Authentication provides a number of ways for health and care workers in England to authenticate their identity when accessing national clinical information systems.

Note: Once you have integrated with NHS CIS2 Authentication and the healthcare worker has successfully authenticated, the calling application receives an ID token that is needed in Step 6: exchange ID token for access token.


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. Best practice is to create one application for each of the test environments you want to access - 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' and 'Manage your applications'.

  4. Select 'New app'.

  5. Enter details for your application and click 'add application' to create it.

  6. Select your application and then 'edit more application details'.
  7. Make a note of the API Key (also known as the Client ID).
  8. In the list of APIs, find the API you want to use and activate it by clicking 'Enable' and 'save'.
  9. Enter the callback URL for your application - you need to enter this even though it's not needed for separate authorisation, so put something like https://www.nowhere.com.


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 healthcare worker with NHS CIS2 Authentication
  • generate a client assertion
  • exchange NHS CIS2 Authentication ID token for access token
  • store our access token for later use

Step 5: Authorise the healthcare worker with NHS CIS2 Authentication

You need to authenticate the healthcare worker with NHS CIS2 Authentication. NHS CIS2 Authentication returns an ID token to the registered callback endpoint on successful authentication.

Your software needs to follow a standard OIDC authorisation code flow with NHS CIS2 Authentication. OIDC clients initiate the NHS CIS2 Authentication authorisation sequence from the browser by calling the NHS CIS2 Authentication authorize endpoint. Once the healthcare worker's authentication is successful, your web server should call the NHS CIS2 Authentication token endpoint 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 this ID token in step 7 and step 9.


Step 6: Generate a client assertion

Before you can call an 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 CIS2 Authentication ID token for access token

Once you have integrated with NHS CIS2 Authentication and the healthcare worker has successfully authenticated, the calling application receives an ID token . Call our token endpoint to exchange the ID token for an access token. This 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.

You need to include the following form parameters in your call:

Parameter Description
subject_token ID token from NHS CIS2 Authentication
client_assertion A signed JWT from step 6
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={NHS CIS2 Authentication ID token}\
--data-urlencode 'client_assertion={jwt token}

If the request is valid, the OAuth 2.0 authorization server responds with an 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 11 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":"43199",
   "token_type":"Bearer"
}

Error scenarios

If there are any issues with your call to our token endpoint, we return an error response, refer to the error scenarios section for errors regarding client assertion and the below table for 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
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 access token for later use

Your access token lasts for 10 minutes and you can use it multiple times. To make more than one API call for the signed in healthcare worker, store your access token securely for later use.

Storing your access token reduces the load on our authorisation server and the chance of your application hitting its rate limit.

For details on what to do when your access token expires after 10 minutes, 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:

  • determine the healthcare worker's role
  • call a user-restricted API
  • refresh our access token
  • request a new access token from us

Step 9: Determine the healthcare worker's role

With NHS CIS2 Authentication, healthcare workers are allocated one or more roles by their Registration Authority, for example, Clinical Practitioner or Nurse.

Some of our APIs require you to send the healthcare worker's role when you call the API.

Some of our APIs also require you to implement national role-based access control (RBAC) within your software to ensure that the healthcare worker only has access to functions and information that are appropriate for their role.

If the healthcare worker has more than one role, they must select a role before using your software.

There are two ways to determine the healthcare worker's role:

1. Custom approach for smartcard users

If the healthcare worker signs in (to a system that has integrated with NHS CIS2 Authentication) with an NHS smartcard, the Identity Agent software on their device prompts them to select a role immediately after they sign in.

Healthcare workers with one role

If the healthcare worker has only one role, the Identity Agent automatically selects it for them. You do not need to send the role in the request header as the API retrieves it from the Identity Agent software on the healthcare worker's machine.

Healthcare workers with more than one role

If the healthcare worker has more than one role, they have to select one of them when prompted by Identity Agent software immediately after they sign in. You do not need to send the role in the request header, as the API retrieves it from the Identity Agent software on the healthcare worker's machine.

For full details on how to do this, see parts 6 and 7 of the Spine External Interface Specification.

Here's a summary:

  1. Call the Identity Agent Ticket API to get the ID token for the healthcare worker's session.
  2. Call the Identity Server to get an SSO Token.
  3. Call the Identity Server to get the SAML Assertion.
  4. Get the ssbSessionRoleUid field from the Person block in the SAML assertion - this is the healthcare worker's selected User Role ID, for example 555021935107.

If the API also requires you to implement national RBAC:

  1. Find the Job Role Profile block in the SAML assertion where the uniqueIdentifier field record matches the above ssbSessionRoleUid.
  2. Get the nhsJobRoleCode field from the same Job Role Profile, for example S0030:G0100:R0570.
  3. Check this against the roles and activities in the national RBAC database.

This is not a standards-compliant approach and does not work for other sign-in methods. If your software is already integrated directly with the Identity Agent, it might be appropriate to retrieve the selected healthcare worker role directly from NHS CIS2. 

2. Standards-compliant approach

You can get a full list of the healthcare worker's roles from NHS CIS2's authentication server, and present them to the healthcare worker to select a role. If the healthcare worker only has one role, you can select it for them automatically.

This approach uses open standards - OAuth 2.0 and Open ID Connect - and works for all types of authentication, not just smartcards.

If you take this approach, healthcare workers signing in with an NHS smartcard will actually be prompted to select a role twice - once by the Identity Agent and once by your software. Their first selection will be ignored.

To use this approach, make an HTTP GET request to NHS CIS2's /userinfo endpoint. For more details on NHS CIS2 environments, see NHS Care Identity Service 2 path to live process.

You need to include the following headers in your call:

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

Note: you should only call this endpoint within an hour of obtaining an access token. Requests made outside of this window will be rejected.

NHS CIS 2 uses standard OpenID Connect scopes to manage what information is available when you call the NHS CIS2’s /userinfo endpoint. To get a list of roles you must include the scope nationalrbacaccess. For a full list of claims returned by NHS CIS2, see Scopes and Claims.

You will receive a response with a JSON response body, containing at least the following fields:

Field Description
nhsid_useruid A 12-digit identifier uniquely identifying the healthcare worker and is commonly referred to as 'SDS User ID'
name The healthcare worker's full name.
nhsid_nrbac_roles An array of the healthcare worker's registered roles

Each of the entries in nhsid_nrbac_roles contains at least the following fields:

Field Description
org_code The organisation's ODS code
person_orgid A 12-digit identifier that uniquely identifies the healthcare worker's association with the organisation
person_roleid A 12-digit identifier that uniquely identifies the healthcare worker's role at the organisation. This is commonly referred to as 'SDS Role Profile ID'
role_code A colon-separated string of codes comprising a Primary, Secondary and Tertiary Job Role Code. This is commonly referred to as 'SDS Job Role Code'
role_name A colon-separated string of names comprising a Primary, Secondary and Tertiary Job Role Name

Here's an example:

{
    "nhsid_useruid": "910000000001",
    "name": "USERQ RANDOM Mr",
    "nhsid_nrbac_roles": [
        {
            "org_code": "RBA",
            "person_orgid": "555254239107",
            "person_roleid": "555254240100",
            "role_code": "S8000:G8000:R8001",
            "role_name": "\"Clinical\":\"Clinical Provision\":\"Nurse Access Role\""
        },
        {
            "org_code": "RBA",
            "person_orgid": "555254239107",
            "person_roleid": "555254242102",
            "role_code": "S8000:G8000:R8000",
            "role_name": "\"Clinical\":\"Clinical Provision\":\"Clinical Practitioner Access Role\""
        },
        {
            "org_code": "RBA",
            "person_orgid": "555254239107",
            "person_roleid": "555254241101",
            "role_code": "S8000:G8000:R8003",
            "role_name": "\"Clinical\":\"Clinical Provision\":\"Health Professional Access Role\""
        }
    ]
}

The response may include extra optional fields. For more details on the possible fields returned, see the national rbac access section of the NHS CIS2 Authentication specification.

API error scenarios

If the healthcare worker role validation is not successful, you get the following error messages when you call a user-restricted API. 

Error scenario HTTP status Error code Description
NHSD-session-URID is invalid 400 BAD_REQUEST nhsd-session-urid is invalid
selected_roleid is missing in your token 400 BAD_REQUEST selected_roleid is missing in your token

Step 10: 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 3>

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 3]"\

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

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 11: 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_tokens 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 healthcare worker.

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 and get new access tokens for up to 12 hours. After 12 hours, 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":"43199",
   "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 12: Request a new access token from us

Using smartcard for authentication will result in a session up to 12 hours. Other authentication methods result in a shorter session of up to an hour. After that time, calls to our token endpoint with a refresh token (so that you can obtain a new access token) returns the following error:

HTTP status Code Description
401 (Unauthorized) invalid_grant refresh token refresh period has expired

If this happens, you must send the healthcare worker back through the full authentication process from step 5 above.

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


Revoking authority

If users authenticate with a smartcard, you need to implement Back Channel Logout within your application to react to a smartcard being removed from a reader. This will not automatically revoke any API access tokens.

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

Last edited: 25 May 2023 2:15 pm