Skip to content
Partner Developer Portal

Partner API - Context Management

Our Partner API context management capability allows our users to initiate your application so that it can obtain tokens in order to call our APIs on behalf of the user.

Point of operation:

Desktop - your application is desktop based and we initiate it to provide Patient/User context

Firstly we need to get you configured, so see Onboarding. When we get you onboarded, we will give you some details that you need to use later.

As part of onboarding we also will ask you to provide us a couple of URLs:

  • launchUrl - address of the launch handler that you implement, you will need to make some calls back to us using the details we provided in this handler in order to obtain tokens.
  • redirectUri - address of the auth handler that you implement to complete the authorization code flow.

As an example, if your custom URI scheme handler was available at partnerapp://partnerapplication, your launch handler was /launch and your auth handler was /auth then your registered URLs would be:

  • launchUrl - partnerapp://partnerapplication/launch
  • redirectUri - partnerapp://partnerapplication/auth

When one of our users initiates your application, we will append some query parameters to the launchUrl: partnerapp://partnerapplication/launch?iss=XXXXXXX&launch=XXXXXXX and then make a GET request to it.

You will need to use the Authorization Code + PKCE flow. This flow consists of these key steps:

  • Generate a code verifier and code challenge
  • Request an authorization code
  • Exchange the authorization code for tokens

Step 1: Generate a Code Verifier and Code Challenge

Section titled “Step 1: Generate a Code Verifier and Code Challenge”

The Authorization Code + PKCE flow requires a code verifier (a random string) and a code challenge (a transformed version of the verifier). The code verifier should be:

  • A cryptographically random string
  • Between 43 and 128 characters long
  • Can contain letters, digits, underscores, hyphens, and periods
Terminal window
# Example of generating a code verifier with OpenSSL
CODE_VERIFIER=$(openssl rand -base64 96 | tr -d '\n' | tr '+/' '-_' | tr -d '=' | cut -c 1-96)
# Example result: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

The code challenge is derived from the code verifier using SHA-256 and Base64URL encoding:

Terminal window
# Example of generating a code challenge with OpenSSL
CODE_CHALLENGE=$(echo -n "$CODE_VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')
# Example result: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM

Construct an authorization URL with your application details and the code challenge:

Terminal window
curl -X POST "https://XXXXXXX.com/XXXXXXX/XXXXXXX/oauth2/v2.0/authorize" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=XXXXXXX" \
--data-urlencode "response_type=code" \
--data-urlencode "redirect_uri=partnerapp://partnerapplication/auth" \
--data-urlencode "response_mode=query" \
--data-urlencode "scope=XXXXXXX" \
--data-urlencode "code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" \
--data-urlencode "code_challenge_method=S256" \
--data-urlencode "state=XXXXXXX" \
--data-urlencode "launch=XXXXXXX"

We will validate the launchID and other parameters, and if valid, will redirect back to your auth handler with an authorization code:

partnerapp://partnerapplication/auth/auth?code=XXXXXXX&state=XXXXXXX

Step 3: Exchange the Authorization Code for Tokens

Section titled “Step 3: Exchange the Authorization Code for Tokens”

Once you have the authorization code, you can exchange it for tokens using a POST request to the token endpoint:

Terminal window
curl -X POST '<https://XXXXXXX.com/XXXXXXX/XXXXXXX/oauth2/v2.0/token>' \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "client_id=XXXXXXX" \
--data-urlencode "scope=XXXXXXX" \
--data-urlencode "code=XXXXXXX" \
--data-urlencode "redirect_uri=partnerapp://partnerapplication/auth" \
--data-urlencode "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

The response will include the tokens:

{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsI...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsI..."
}

Within the ID token we issue to your application, we embed patient context so that you can use it as required. An example base64 decoded payload of an ID token:

{
"exp": 1744876486,
"nbf": 1744872886,
"ver": "1.0",
"iss": "https://XXXXXXXXXXXXX/v2.0/",
"sub": "XXXXXXXXXXXXX",
"aud": "XXXXXXXXXXXXX",
"acr": "XXXXXXXXXXXXX",
"nonce": "204b601d-a7fc-440a-b863-0667d2307131",
"iat": 1744872886,
"auth_time": 1744872885,
"email": "luke.smith@emishealth.com",
"userERN": "ern:emis:user:user:XXXXXXXXXXXXX",
"title": "Mr",
"firstName": "Luke",
"familyName": "Smith",
"orgERN": "ern:emis:org:org:XXXXXXXXXXXXXd",
"orgName": "BURNHAM SURGERY",
"cdb": "50002",
"ods": "XXXXXXXXXXXXX",
"authorizations": [
"agmt-agmt.read",
"clinical-cr.read",
"clinical-cr.write",
"doc-app.addcode",
"doc-app.create",
"term-prep.read"
],
"authorizationDetails": "[{\"forenames\":\"Ray\",\"surname\":\"Keates\",\"gender\":\"Male\",\"dob\":\"12-Oct-1955\",\"title\":\"Mr\",\"type\":\"patient-context\",\"version\":\"1.0.0\",\"patient-identifiers\":[{\"identifierType\":\"GUID\",\"identifierValue\":\"XXXXXXXXXXXXX\"},{\"identifierType\":\"EHR Partner ID\",\"identifierValue\":36},{\"identifierType\":\"NHS Number\",\"identifierValue\":\"XXXXXXXXXXXXX\"}],\"address-details\":[{\"addressLine1\":\"\"}],\"contact-details\":[]}]",
"at_hash": "aSTOTTzIbbMNHsrdmGe39g"
}

Note the authorizationDetails claim.

The sequence diagram below depicts the expected flow:

sequenceDiagram
    actor User as User
    participant Source as EMIS-X Application
    participant Client as Partner Application
    participant IdP as EMIS-X Identity Provider
    participant Resource as EMIS-X API

    %% User initiates launch
    activate User
    User->>Source: Initiates launch
    deactivate User
    activate Source

    %% Launch sequence
    Source->>IdP: Request launchID
    activate IdP
    IdP->>IdP: Generate launchID
    IdP-->>Source: Return launchID
    deactivate IdP

    Source->>Client: GET {launchURL}?launch={launchID}
    activate Client
    deactivate Source

    Note over Client: Store launchID

    %% PKCE preparation
    Client->>Client: Generate Code Verifier
    Client->>Client: Create Code Challenge
(SHA-256 hash of Code Verifier) %% Authorization request Client->>IdP: POST /authorize
with client_id, redirect_uri, code_challenge, launchID activate IdP Note over IdP: Validate launchID
(and other params) IdP-->>Client: Return Authorization Code deactivate IdP %% Token exchange Client->>IdP: POST /token
with code, code_verifier, client_id activate IdP Note over IdP: Verify Code and
Code Verifier match IdP-->>Client: Return Access, ID & Refresh Tokens deactivate IdP Client->>Client: Decode ID token to get patient context %% User interacts with client after auth Client-->>User: Display authenticated interface activate User User->>Client: Interact with application Note over Client: User initiates resource request %% Using the tokens Client->>Resource: Request with Access Token activate Resource Note over Resource: Validate token Resource-->>Client: Protected Resource Response deactivate Resource Client-->>User: Display resource response deactivate User deactivate Client