OAuth2 client walkthrough

Overview

Authentication and authorisation in PKB are through OAuth 2.0, the same open standard that Facebook, Google, Twitter and Yahoo! have adopted.

Below is a full walkthrough of the OAuth2 path that PKB uses for patient and clinician authentication, controlling access to the REST API.

This is the basic OAuth2 public client implementation with bearer tokens, with no custom oddities, extensions, or special requirements.

Sandbox vs. Production

All links below reference sandbox.patientsknowbest.com; this is a testing server with only demo users and data.

To run against production, change the domain to my.patientsknowbest.com

Bypassing authentication for connectivity testing

The web interface login for the PKB test server is located here: https://sandbox.patientsknowbest.com


There are 3 test accounts that you can use to test the logins. To access the web interface, use the usernames and passwords provided in the table below. To bypass the OAuth2 flow to test the REST API, simply provide the corresponding bearer token.

User Type Username Password Test Bearer Token
PATIENT florencepenguin@pkbtest.com P@55word Bearer testPatient
CLINICIAN paulpenguin@pkbtest.com P@55word Bearer testClinician
TEAM COORD pingupenguin@pkbtest.com P@55word Bearer testTeamCoord

Obtain a Client ID

In order to authenticate against the REST API you will first need to obtain a Client ID. This allows us to identify your connection.

Authenticating with a User Client ID

1. App sends user to PKB's authorization endpoint in a browser

Description

The client should generate a URL as follows, and then send the user to that URL in a browser.

Method  HTTP GET
URL
https://sandbox.patientsknowbest.com/apiAuthorize.action

Parameters

Parameter Type Optionality Description Example
response_type Query parameter Required Must be "code" code
client_id Query parameter Required The REST API Client ID previously issued to you myClientId
scope Query parameter Optional Allowed values are:
  • PATIENT
  • CLINICIAN
  • TEAMCOORD
If a value is not provided, we will permit a user from any scope that has has been enabled for your REST API Client ID.
PATIENT
state Query parameter Optional Although this is optional, it is strongly recommended. This should be an opaque value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery, as described in Section 10.12. ANTI_CSRF_0479274
redirect_uri Query parameter Conditional If you have several redirect URIs registered against your Client ID, then you must specify this parameter. Otherwise, it is optional.

If you do specify this parameter, you can add additional parameters to the URI on top of the base URI that is associated with your Client ID.

You are not able to specify a new URI with this parameter.
https://client.example.com/cb

Example

An example of a complete URL is shown below.

https://sandbox.patientsknowbest.com/apiAuthorize.action?response_type=code&client_id=myClientId&redirect_uri=https://client.example.com/cb&scope=PATIENT&state=ANTI_CSRF_0479274

Redirect URL

Paypal Example:
  • You buy a number of items from a retailer’s website
  • You elect to pay via Paypal
  • Retailer sends you off to Paypal’s payment page and include details about how much you need to pay
  • On paypal’s page, you login and agree to pay the specified retailer
  • On completion of payment, Paypal needs to know where to send you back to. This is the redirect URL

To be PKB specific,
  • In order to gain access to a user’s data, the user needs to approve.
  • You present the user with PKB’s authorization URL (within your app)
  • The user is then presented with PKB’s login page. After login, PKB let's the user know that you’re requesting access to their account
  • if the user approves, PKB needs to know what URL(on your side) to send the user back to
  • This url will contain a code which you would then use to retrieve a pair of token that would allow you to fetch that user’s data

For mobile apps(at least the android ones), this url doesn’t need to be a real one. So if you had your redirect_uri set to mobileapp://foo.bar.code and your mobile app is configured to intercept that call, then that would work too.


Error handling

If there's a problem with the client_id or redirect_uri, PKB will show an explanation to the end user in the page returned instead of a login form.

Otherwise, error handling will be as outlined in the next step.

2. PKB prompts users for credentials, then redirects them

Description

Having sent the user to the login page, PKB will show information about who owns the Client ID, and prompt them to enter their credentials if they wish to approve the access request. The user will either do this and click "Approve", else they can click "Deny".

If the user clicks "Approve" and the authentication is successful, PKB will redirect the user to the specified redirect_uri. If one was not specified, then the single redirect URIs associated with the Client ID will be used. If there are multiple URIs, and one was not specified, then an error page will be shown.

Note: the authorization code is bound to the Client ID and the redirection URI -- the client will need to use the same redirection URI for the next step as well.

Parameters

Parameter Type Optionality Description Example
code Query parameter Required The authorization code that can subsequently be used to obtain an access token SplxlOBeZQQYbYS6WxSbIA
state Query parameter Optional The same value that was sent in the request, if present ANTI_CSRF_0479274

Example

An example redirect is shown below.

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=ANTI_CSRF_0479274

Error handling

If user clicks "Deny", user fails auth attempt, scope value isn't recognized or request is otherwise malformed, PKB sends the redirect like this:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?error=access_denied&state=ANTI_CSRF_0479274

See section 4.1.2.1 for more information on error codes.

3. App exchanges authorization code for access token

Request

Description

Once you have an authorization code, you can swap this for an access token (and possibly a refresh token too).

Method  HTTP POST
URL
https://sandbox.patientsknowbest.com/apiToken.action

Parameters

Parameter Type Optionality Description Example
grant_type Form parameter Required Must be "authorization_code" authorization_code
client_id Form parameter Required The REST API Client ID previously issued to you myClientId
code Form parameter Required The authorization code returned in the previous step SplxlOBeZQQYbYS6WxSbIA
redirect_uri Form parameter Conditional If you specified one in the original request, this must match exactly. Otherwise, this is optional. https://client.example.com/cb

Example

POST /apiToken.action HTTP/1.1
Host: sandbox.patientsknowbest.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&client_id=myClientId&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https://client.example.com/cb

Response

Description

PKB responds with the access token in JSON, and possibly a refresh token too.

Parameters

Parameter Type Optionality Description Example
access_token JSON parameter Required This is the access token that can subsequently be used to authenticate against the PKB REST API, and gain access to the functionality 2YotnFZFEjr1zCsicMWpAA
token_type JSON parameter Required This is always "Bearer" Bearer
expires_in JSON parameter Required This indicates the number of seconds for which the access_token is valid 600
refresh_token JSON parameter Optional If the session has not expired, a refresh_token will also be issued. This can be used to obtain a new access_token when the token validity period has expired. tGzv3JOkF0XG5Qx2TlKWIA
scope JSON parameter Optional This will match the scope specified in step 1 PATIENT


Example

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache


{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"Bearer",
"expires_in":600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"scope":"patient"
}

Error handling

The authorization code is only valid for a short duration. If that duration expires, or if a previously used authorization code is submitted again, then an error is returned. Using an authorization code twice will invalid any token granted from the initial usage.

Example Error

HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache


{
"error":"invalid_request"
}

See section 5.2 for a full list of error response codes.

4. App exchanges refresh token for new access token (when expired or rejected)

Request

Description

An access token is only valid for a short duration (normally 10 minutes). After that, a new access token can be requested using a refresh token. This will be possible until the session expires (unless your Client ID is configured to have non-expiring sessions).

Refresh tokens can only be used once. If one is submitted that has previously been used, all active tokens for that session will be revoked.

Method  HTTP POST
URL
https://sandbox.patientsknowbest.com/apiToken.action

Parameters

Parameter Type Optionality Description Example
grant_type Form parameter Required Must be "refresh_token" refresh_token
client_id Form parameter Required The REST API Client ID previously issued to you myClientId
refresh_token Form parameter Optional The refresh token issued at the same time as the most recently valid access token tGzv3JOkF0XG5Qx2TlKWIA
scope Form parameter Optional The scope of the session PATIENT

Example

POST /apiToken.action HTTP/1.1
Host: sandbox.patientsknowbest.com
Content-Type: application/x-www-form-urlencoded


grant_type=refresh_token&client_id=myClientId&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&scope=PATIENT

Response

Description

PKB responds with a new access token in JSON, and possibly a refresh token too (if the session hasn't expired).

Example

Same as for the initial token request above.

Error handling

Same as for the initial token request above.

Practical Implementation

In order for an external system or application to successfully make API calls they must have a valid authorization token. This can be achieved in a number of ways. 
One solution involves programmatically requesting refresh tokens before going stale.
Another implementation involves requesting refresh tokens when an API request errors due to authentication then resubmitting the request with the new refresh token. 

Authenticating with a System Client ID

1-3. PKB Team Coordinator generates access and refresh tokens in web interface

If you are using the REST API from a fixed endpoint, e.g. a hospital, and do not require individual patients to log in, then you can obtain an access token using the GUI. You will need to login to the PKB GUI as the Team Coordinator for whom you would like to authenticate, and then click on the "REST API access" button from the "Institution" tab.


Enter your System Client ID and a new pair of access and refresh tokens will be displayed.

You should then be able to use this access token directly, without needing to go through the authorization workflow described above.

4. System exchanges refresh token for new access token (when expired or rejected)


To refresh your access token, you will need to follow the same steps as outlined in step 4. above, but you must always send a scope of SITE.

Exactly the same restrictions regarding session timeouts and token reuse apply, regardless of whether you connect using a System or User Client ID.


Accessing secured API functionality


Description

Once a valid access token has been obtained, it should be appended to "Bearer " (note the trailing space) to form the value for the  "Authorization" parameter, which is required by the secured operations in the PKB REST API.

Example

GET /json/users/self HTTP/1.1
Host: sandbox.patientsknowbest.com
Authorization: Bearer testPatient

Screenshot


Error handling

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"


Comments