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.
You need a separate application for each environment.
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.
Selecting a role
If the healthcare worker has more than one role, they must select a role before using your software.
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.
To get the list of roles, 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:
{
"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\"",
"activity_codes":[
"B0021",
"B0022",
"B0019"
],
"activities":[
"Perform Discharge Administration",
"Print Discharge Summary",
"View Discharge Summary"
]
},
{
"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 nationalrbacaccess section of the CIS2 Authentication specification.
Smartcard users and the Identity Agent
Healthcare workers signing in with an NHS smartcard and still using the legacy Identity Agent will actually be prompted to select a role twice if they have multiple roles - once by the Identity Agent and once by your software. Their first selection will be ignored.
The Identity Agent is expected to be retired in February 2027, and you should therefore not rely on using it to select the user's role.
Checking the user is authorised
To check the user is authorised to access the API, follow the steps in Implementing national RBAC. The relevant API specification might include details of which activity codes are suitable for the API. If not, you'll need to decide for yourself based on the meanings given in the national RBAC database.
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 |
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 August 2026 8:52 am