Skip to main content

Digital Staff Passport API standard - authorisation using OAuth 2.0 private key JWT

How to secure external applications for the Digital Staff Passport using OAuth 2.0 private key JWT.

Overview

The Digital Staff Passport API standard requires external systems to secure their API using OAuth 2.0 private key JWT. This page explains how to do that.

OAuth 2.0 is an open standard for API authorisation and is generally considered to be the best way to secure modern RESTful APIs.

Private key JWT is a type of OAuth 2.0 authorisation where the calling application strongly authenticates itself by creating and signing a JSON Web Token (JWT). Unlike some other types of OAuth 2.0, an end user is not involved - this is a system-to-system, or 'application-restricted', form of authentication.

This approach is deemed suitable for APIs that handle personal or sensitive data within the NHS in England.


How this pattern works

In this pattern, Digital Staff Passport (DSP) authenticates itself by sending a signed JSON Web Token (JWT) to an OAuth 2.0 authorisation server that you provide. 

DSP provides you with its public key and signs the JWT with its private key. In return, your OAuth 2.0 server gives DSP an access token, which it then includes with each API request.

The following diagram illustrates the pattern:

Diagram illustrating the data flows when authorisation using OAuth 2.0 private key JWT

The following sequence diagram shows how the various components interact:

Diagram illustrating how components interact when authorisating using OAuth 2.0 private key JWT

In words:

  1. The end user, if present, launches the calling application - in this case DSP.

  2. Time passes, until the user needs to access an application-restricted API.

  3. The calling application generates and signs a JWT, using its own private key.

  4. The calling application calls the OAuth 2.0 token endpoint with the signed JWT. In particular, this uses the OAuth 2.0 client credentials flow.

  5. The OAuth 2.0 server checks the signature against the application's public key, and returns an access token to the calling application.

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


Pattern variations

In order to support a wide variety of tech stacks, we've provided pattern variations that we know are suitable for specific platforms and tools.

If you would like us to consider any further variations, contact us.

Default pattern

The default pattern uses 'vanilla' private key JWT, in which:

  • in step 2, we'll supply you with the URL for our public key JWKS
  • in step 3, we'll populate the iss field with the client_id you provide

Pattern variation 1: federated identity

This pattern variation uses OpenID Connect Discovery to publish our public keys. This is suitable for teams using Microsoft Azure because it aligns with using Microsoft identity platform with a federated credential.

In this pattern:

  • in step 2, we'll supply you with the URL for our OIDC 'well known' endpoint
  • in step 3, we'll populate the iss field with our OIDC issuer URL

Detailed integration instructions

The following sections explain in detail how to implement this security pattern.

You might also find it useful to refer to the guidance that explains how we use signed JWT to secure our own APIs: Application-restricted RESTful APIs - signed JWT authentication.


Step 1: DSP generates a key pair

This step happens during system configuration.

DSP generates a 4096-bit RSA private/public key pair.

Note that:

  • DSP generates separate key pairs for each environment.
  • Within each environment, DSP generates a separate key pair for each NHS organisation.
  • Within a given environment, DSP might use the same private/public key pair across multiple integrations.

DSP then:

For more details on how DSP generates a key pair, or to generate a key pair and JWKS for testing, see Step 2: generate a key pair on our Signed JWT authorisation guidance page. You can also use our API platform to publish your public key JWKS for testing - see Step 3: register your public key with us, and use the option to "Ask us to host your public key".

Here's an example public key JWKS containing two separate public keys (the purpose of having multiple keys is to allow for periodic key rotation):

{
  "keys": [
    {
      "kty": "RSA",
      "e": "AQAB",
      "use": "sig",
      "kid": "DSP_TEST_1",
      "alg": "RS512",
      "n": "ApKKL1BY_itCl3EDTTlLJzuP33Rl6LbEaDsk75GxdyXzXb0jsbWQ-fG3b2i0T-efcJfmuHvzzAk6NoOSwnG_kRhb6b_n924MyqkGS6_Mb1wMhZdd4GQCU1c0vJLRVYTvrySq9L4M4CP2yCdyHXFv57kanA-R3nRUNO6tIkRWsdD2VVwm6dII_QTnSpKrRgyt0DyYImRxsa52AdpdFAArXiIR1OZgkuwJn8l-6yKT6iXUYhgfI6Pgl3XgJ3i06DDjpkUG-zTpyFlpnxLfgvZ8P-Q6LXvfazWItzDYM5xe37RL8zkus2mip5FCgKHu5Ed59CPYkto2YRaRUKvSoZ1BYPLfMjfEQuHPpqvmfL4MG8N7dzUAHRI6mDuOrWTsxyqJHV-I2MYPEPJx1YlZS-mbpbJj6oQmwWxXvld2X-clvNjePa6CD3R6U6pBnc9y_3luj_JrkKItUqAxBxhIBGM1GdeCJnogDEypXQIOKBMZpy6er_EHFbRXtgQEJ-snIY0TITnsOyjmpyrFWv2pa-fe4jtAPeeo4jUJfcw6iAHbN31WcMfg0GNnV4Td_BmcdmvihbV827_3OmqHdt9HEWJCtkWJvZcDN09WifTdBNvXwy9vKyAHRdmkGG-pdq_JFWt661Y7Dm9ubSN58OzO6uyVOJMHdIpcCjtPb8mkQ8rFheax"
    },
    {
      "kty": "RSA",
      "e": "AQAB",
      "use": "sig",
      "kid": "DSP_TEST_2",
      "alg": "RS512",
      "n": "Ah-ekOAyAvmO3ZCxCyUWNwGQRR52sMbtWLVPLoFvA0JlCg_qWdtQvsEt4t5KuT0Ujf7h0vcOJJvDwfWX8j1dVFlDR7SMEa48hodw0xqlKRp82LCwl4nScK_OWN7eVgsofyLedfnTKnGlixaROYn7Tt6RGPPO9A1PizEI3bUhC39fo6JwxWNFba_PIMdLFwI2jPwpja4gxNlFUOK-T9HXPxhtLgx6lcrJOL5YHLld9g5pP2JwLl8XvvzlQ295p-tFfV6zRGcIf5t2oHNkFbADo4aYK7FvbK1afJGILYjQgYCJtRZarkU2fb47izyCRJBXnzqPWlh2X3FI7ib6fRwlaTiTj6Rcj2XKrYUBI9nCSaQa8euSw2tNLYAUNPXhKW35hK1CYG5ZKNGrXph6tjJlqTxgQjE2oyciyVPAI_cjyNxaXiPbor7r9ffiFL-Ck75q9IeH1saj7zISziTTMLmK84IC9l3ARRbsZ9eFr7YswDNuHL0ghqTpr9RejzXinWydBLoHSyl06dG4hjX5tlDqutK0PGRhi9pX9EpPqn0wTm3GfOn06C8wtjQDuSECrAlAUskVKDJ0q9e7bZnX5R3izBm30mx2yXTJf7w_iR079h_LMEijzuKhs8LZIpNU3RgVgqkGPnOCPtLt3SpFfExSYAunhslZ9i_bvrX5u-Kp-fLH"
    }
  ]
}

We've also published this public key JWKS at a URL that you can use for testing.

The associated private and public keys are also available below in X.590 PEM format.

DSP_TEST_1 private key

-----BEGIN PRIVATE KEY-----
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
2jAus18iWG8xu+oNjZjM0eDgW1zJYI11ag==
-----END PRIVATE KEY-----

DSP_TEST_1 public key

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgECkoovUFj+K0KXcQNNOUsn
O4/fdGXotsRoOyTvkbF3JfNdvSOxtZD58bdvaLRP559wl+a4e/PMCTo2g5LCcb+R
GFvpv+f3bgzKqQZLr8xvXAyFl13gZAJTVzS8ktFVhO+vJKr0vgzgI/bIJ3IdcW/n
uRqcD5HedFQ07q0iRFax0PZVXCbp0gj9BOdKkqtGDK3QPJgiZHGxrnYB2l0UACte
IhHU5mCS7AmfyX7rIpPqJdRiGB8jo+CXdeAneLToMOOmRQb7NOnIWWmfEt+C9nw/
5Dote99rNYi3MNgznF7ftEvzOS6zaaKnkUKAoe7kR3n0I9iS2jZhFpFQq9KhnUFg
8t8yN8RC4c+mq+Z8vgwbw3t3NQAdEjqYO46tZOzHKokdX4jYxg8Q8nHViVlL6Zul
smPqhCbBbFe+V3Zf5yW82N49roIPdHpTqkGdz3L/eW6P8muQoi1SoDEHGEgEYzUZ
14ImeiAMTKldAg4oExmnLp6v8QcVtFe2BAQn6ychjRMhOew7KOanKsVa/alr597i
O0A956jiNQl9zDqIAds3fVZwx+DQY2dXhN38GZx2a+KFtXzbv/c6aod230cRYkK2
RYm9lwM3T1aJ9N0E29fDL28rIAdF2aQYb6l2r8kVa3rrVjsOb25tI3nw7M7q7JU4
kwd0ilwKO09vyaRDysWF5rECAwEAAQ==
-----END PUBLIC KEY-----

DSP_TEST_2 private key

-----BEGIN PRIVATE KEY-----
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
c+YeSof6qLOv3HbDX+oVVeNec/dQ3epZ6g==
-----END PRIVATE KEY-----

DSP_TEST_2 public key

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgECH56Q4DIC+Y7dkLELJRY3
AZBFHnawxu1YtU8ugW8DQmUKD+pZ21C+wS3i3kq5PRSN/uHS9w4km8PB9ZfyPV1U
WUNHtIwRrjyGh3DTGqUpGnzYsLCXidJwr85Y3t5WCyh/It51+dMqcaWLFpE5iftO
3pEY8870DU+LMQjdtSELf1+jonDFY0Vtr88gx0sXAjaM/CmNriDE2UVQ4r5P0dc/
GG0uDHqVysk4vlgcuV32Dmk/YnAuXxe+/OVDb3mn60V9XrNEZwh/m3agc2QVsAOj
hpgrsW9srVp8kYgtiNCBgIm1FlquRTZ9vjuLPIJEkFefOo9aWHZfcUjuJvp9HCVp
OJOPpFyPZcqthQEj2cJJpBrx65LDa00tgBQ09eEpbfmErUJgblko0atemHq2MmWp
PGBCMTajJyLJU8Aj9yPI3FpeI9uivuv19+IUv4KTvmr0h4fWxqPvMhLOJNMwuYrz
ggL2XcBFFuxn14WvtizAM24cvSCGpOmv1F6PNeKdbJ0EugdLKXTp0biGNfm2UOq6
0rQ8ZGGL2lf0Sk+qfTBObcZ86fToLzC2NAO5IQKsCUBSyRUoMnSr17ttmdflHeLM
GbfSbHbJdMl/vD+JHTv2H8swSKPO4qGzwtkik1TdGBWCqQY+c4I+0u3dKkV8TFJg
C6eGyVn2L9u+tfm74qn58scCAwEAAQ==
-----END PUBLIC KEY-----

Step 2: DSP registers with your API

This step happens during system configuration.

The DSP team registers DSP with you for a specific NHS organisation.

Ideally, you provide a user interface for the DSP team to use, but alternative processes, such as a service request, are acceptable.

During registration:

  • the DSP team shares its NHS organisation-specific public key URL with you
  • you provide the DSP team with an organisation-specific client ID as per the OAuth2.0 standard

Step 3: DSP generates and signs a JWT

This step happens during operational use of DSP.

Specifically, it happens when DSP needs to use your API, but only if DSP doesn't already have an active access token.

DSP generates and signs a JWT for use in step 3.

The JWT consists of three parts:

  • header
  • payload
  • signature

Payload

The JWT payload includes the following fields:

Field Description Type
iss The issuer of the JWT. By default this is the client ID you issued to DSP in step 1, but if you're using pattern variation 1, it is the issuer URL as per our OIDC 'well known' endpoint. string
sub The subject of the JWT - the client ID. string
aud The audience of the JWT - the URI of the token endpoint DSP is calling, for example https://<YOUR-DOMAIN>/oauth2/token for your production environment. string
exp Expiry time of the JWT, expressed as a Numeric Time value - the number of seconds since epoch (for example, a UNIX timestamp). This is set to 5 minutes after the time of creation of the JWT. number
iat

Issue / creation time of the JWT, expressed as a Numeric Time value - the number of seconds since epoch (for example, a UNIX timestamp).

API providers can choose whether to do anything with this claim. It has only been included in the specification because the Microsoft identity platform federated credential pattern mentioned in security pattern variation 1 requires it to be present.

number

Example

{
  "iss": "<test-app-api-key>",
  "sub": "<test-app-api-key>",
  "aud": "https://<YOUR-DOMAIN>/oauth2/token",
  "exp": "<current-time-plus-5mins-from-jwt-creation>",
  "iat": "<current-time>"
}

Signature

The JWT signature consists of the contents of the header and payload, signed with the appropriate private key.

Assembling the JWT

The complete JWT consists of:

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

Generating a test JWT

You can generate a JWT for testing at https://jwt.io/.


Step 4: DSP gets an access token

This happens immediately after step 3.

Once it has a signed JWT, DSP makes a call to your OAuth 2.0 server's token endpoint.

Specifically, this is an HTTP POST . We recommend the following URLs for your token endpoint:

Environment Token endpoint
Integration test https://integration-test.<yourdomain>/oauth2/token
Production https://<yourdomain>/oauth2/token

DSP includes the following data in the request body in x-www-form-urlencoded format:

  • grant_type = client_credentials
  • client_assertion_type = urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • client_assertion = <the signed JWT from step 3>

Here's a complete example, as a CURL command:

curl -X POST -H "content-type:application/x-www-form-urlencoded" --data \
"grant_type=client_credentials\
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer\
&client_assertion=<DSP'S-SIGNED-JWT>" \
https://<YOUR-DOMAIN>/oauth2/token

Your token endpoint must validate the request as per the OAuth2.0 specification, including, but not limited to:

  • verifying the signature against the appropriate public key for the given client ID (iss field) and key identifier (kid field)
  • checking the JWT hasn't expired (exp field)

Your token endpoint must then respond with a JSON response body containing the following fields:

  • access_token - the access token DSP uses when calling your API
  • expires_in - the time after which the access token will expire, in seconds, which is ideally 600 and must be a maximum of 3600
  • token_type - must be Bearer

Here's an example response:

{'access_token': 'Sr5PGv19wTEHJdDr2wx2f7IGd0cw',
 'expires_in': '600',
 'token_type': 'Bearer'}

Refresh tokens

You do not need to include a refresh token in your response.

Error scenarios

If there are any issues with DSP's call to your token endpoint, you must return an appropriate error response, as per the OAuth2.0 specification.


Step 5: DSP calls your API

As appropriate, DSP calls your API as described in the Digital Staff Passport API standard.

DSP includes the following header in its call:

  • Authorization = Bearer <access token from step 4>

Here's an example, using a CURL command:

curl -X GET https://<YOUR-DOMAIN>/dsp-api/employees/12345 \
-H "Authorization: Bearer <access token from step 4>"

Your API must validate the Authorization header as per the OAuth2.0 specification, and return a suitable error if validation fails.


Step 6: DSP refreshes its token

DSP's access token expires after a period of time, as per the expires_in parameter - by default this is 600 seconds (10 minutes).

After that, calls to your API must return an HTTP status code of 401 (Unauthorized).

You do not need to provide a method for DSP to refresh its access token. If the token expires, DSP will get a new token, repeating the above process from step 3.


Step 7: DSP rotates its key pairs

Periodically, DSP rotates its key pairs, as follows:

  1. DSP generates a new key pair, as per step 1.
  2. DSP adds the new public key to its published public key JWKS, with a new kid, alongside the existing public key.
  3. DSP starts using the new private key to sign its JWTs, as per step 3.
  4. DSP removes the old public key from its published public key JWKS.

You do not need to take any action when DSP rotates its key pairs.

You just need to make sure you always validate the JWT signature against the appropriate public key for the given client ID and KID in step 4.

Last edited: 15 January 2025 2:17 pm