User-restricted RESTful APIs - CIS2 combined authentication and authorisation
Learn how to integrate your software with our user-restricted RESTful APIs - using our CIS2 combined authentication and authorisation pattern.
Overview
This page explains how to integrate your software with our user-restricted RESTful APIs.
In particular, it describes the CIS2 combined authentication and authorisation pattern, which uses our OAuth 2.0 authorisation server.
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 a simpler integration
- you do not need the healthcare worker's identity information
In particular, this pattern is not appropriate when building GP software.
How this pattern works
In this pattern, authentication and authorisation are done together. Authentication is done by CIS2 Authentication but we co-ordinate that under the covers behind our OAuth2.0 authorisation server. Your application only needs to be registered with the API Platform, not CIS2.
The healthcare worker authenticates with either an NHS smartcard or a modern alternative.
The following diagram illustrates the pattern:
The following sequence diagram shows how the various components interact:
In words:
- The healthcare worker launches the calling application.
- The calling application redirects the healthcare worker's browser to our OAuth2.0 authorisation endpoint (/oauth2/authorize).
- The healthcare worker signs in to their CIS account (using a smartcard and PIN or other authenticator).
- Our authorisation server redirects control back to the calling application, with an authorisation code.
- The calling application calls our OAuth2.0 token endpoint (/oauth2/token), with the authorisation code, and receives an access token in return.
- Time passes, until the healthcare worker needs to access a user-restricted API.
- The calling application calls the user-restricted API, including the access token.
Using this pattern with CIS1
If you are already using CIS1 Authentication in your application, see Using CIS2 with CIS1 for API access.
Tutorials
Detailed integration instructions
The following diagram shows the high level integration phases with the API platform and the sections below it explain in detail how to use this security pattern.
Environments and testing
As well as production, we have a number of test environments. Each environment is paired with a suitable CIS2 environment. In the steps below, make sure you use the appropriate URL base path:
Environment | Sign-in method | Availability | URL base path | Paired CIS2 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 - using our mock authorisation service | All APIs | int.api.service.nhs.uk/oauth2-mock | Not applicable |
Integration test | CIS2 - smartcard and PIN or modern alternative | All APIs | int.api.service.nhs.uk/oauth2 | Integration (INT) |
Production | CIS2 - smartcard and PIN or modern alternative | 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 on the API platform
- trigger the authorisation journey
- healthcare worker completes authentication and authorisation
- receive authorisation results
Step 1: Register your application on the API platform
To use this pattern, you need to register an application. This gives you access to your API Key and Secret, and allows you to specify your Callback URL, all of which you will need later in the process.
- If you do not already have one, create a developer account.
- Navigate to my developer account and sign in.
- Select 'Environment access' on my developer account.
- Select 'Add new application'.
- Enter the details of your application including application owner and application name to create your new application.
- Select 'View your new application' to check or edit your application details.
- 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.
- Click the 'Add APIs' button to add the API you want to use.
- Enter the Callback URL for your application. See step 4 for more details.
For the Hello World (Sandbox) example, you need to select the API "Hello World API - User Restricted (Sandbox)".
Step 6: Store 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.
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);
}
}
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 your access token
- request a new token from us
Step 7: Determine the healthcare worker's role
With CIS, 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 their CIS account 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. However, if you need to override the selected role, you can send another role in the request header, which we then validate against the healthcare worker’s information.
To get the full list of the healthcare worker's roles, make an HTTP GET request to our /userinfo endpoint:
https://api.service.nhs.uk/oauth2/userinfo
To do this, you need the access token from step 5 above,
Error scenarios
If the healthcare worker's role validation is not successful, you get the following error messages when you call a user restricted API. Follow steps 2 to 5, to avoid selected_roleid error message.
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 |
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 CIS.
For full details on how to do this, see parts 6 and 7 of the Spine External Interface Specification.
Here's a summary:
- Call the Identity Agent Ticket API to get the ID token for the healthcare worker's session.
- Call the Identity Server to get an SSO Token.
- Call the Identity Server to get the SAML Assertion.
- 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:
- Find the Job Role Profile block in the SAML assertion where the uniqueIdentifier field record matches the above ssbSessionRoleUid.
- Get the nhsJobRoleCode field from the same Job Role Profile, for example S0030:G0100:R0570.
- Check this against the roles and activities in the national RBAC database.
2. Standards-compliant approach
You can get a full list of the healthcare worker's roles from our authorisation server, and present them to the healthcare worker to select a role. If the healthcare worker has only one role, you can select it for them automatically.
This approach uses open standards - OAuth 2.0 and Open ID Connect - and will work 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 our /userinfo endpoint:
https://api.service.nhs.uk/oauth2/userinfo
Note: the above URL is for our production environment. For other environments, see Environments and testing.
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.
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:
The response may include extra optional fields. For more details on the possible fields returned, see the nationalrbacaccess section of the CIS2 Authentication specification.
Step 8: Call a user-restricted API
Once you have an access token, you can call a user-restricted API.
You need to include the following headers in your call:
- Authorization = Bearer <your access token from step 5>
- NHSD-Session-URID = <healthcare worker role ID from step 7> (optional - not all APIs require this)
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 5]" \
-H "NHSD-Session-URID: [healthcare worker role ID from step 7]"
Note: the URL in the above example is for our sandbox environment. For other environments, see Environments and testing.
All being well, you’ll 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 will return an error response as follows:
Error scenario | HTTP status | Error code |
---|---|---|
Access token is missing | 401 (Unauthorized) | invalid_credentials |
Access token is invalid | 401 (Unauthorized) | invalid_credentials |
Access token has expired | 401 (Unauthorized) | invalid_credentials |
For details of API-specific error conditions, see the relevant API specification in our API and integration catalogue.
Step 9: Refresh your access token
Your access token expires after 10 minutes and must be refreshed.
If your access token has expired, when you call a user-restricted API, you receive a response with an HTTP status code of 401 (Unauthorized) and an error code of invalid_credentials.
To refresh the access token, submit the expired token's corresponding refresh token to our token endpoint using grant_type of refresh_token .
You can continue to request new access tokens for up to 12 hours. When you refresh an access token, you get a new access token and it invalidates the original access token immediately. You also get issued a new refresh token to replace the one you just used.
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 URL in the above example 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
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 |
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 |
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 |
{
"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\""
}
]
}
Step 10: Request a new access token from us
You can continue to request new access_tokens for up to 12 hours.
After that, calls to our token endpoint return an HTTP status code of 400 (Bad Request) and an error code of invalid_request.
If this happens, you must send the healthcare worker back through the full authorisation process from step 2 above.
Note that CIS2 session cookies last for 12 hours, so the healthcare worker does not need to re-authenticate. However, the system might check, for example, that their smartcard is still inserted.
Last edited: 11 June 2025 12:33 pm