Authentication
OAuth 2
Authentication is handled via SALUS Guardian, the Identity provider for all SALUS API services. The Developer API thus
expects a valid JWT token to be present with every request, and validates that the token was generated by the Guardian
IdP. Each environment has its own Guardian IdP instance; in this way, applications can clearly target distinct
environments in isolation.
The Guardian IdP supports the following authentication flows:
- client credential grant - for confidential clients
- authorization code grant (with PKCE) - both for public and confidential clients
Client Credentials Grant
The client credential grant flow is designed to facilitate integration with non-interactive system-level applications. A good example of this would be an integration service. As such, the client_id
and client_secret
grant the bearer fairly unrestricted access, usually at the company_owner
level. This ensures the service will operate on all required data.
To generate the bearer token, use the client_credentials
authorization grant protocol flow against the Guardian IdP.
The authentication credentials can be passed using the JSON body or using a HTTP Basic Auth header.
curl -X POST --location '<<token_url>>' \
--header 'Content-Type: application/json' \
--data '{
"grant_type": "client_credentials",
"client_id": "<<CLIENT_ID>>",
"client_secret": "<<CLIENT_SECRET>>",
"scope": "sls:idn"
}'
curl -X POST --location '<<token_url>>' \
--header 'Content-Type: application/json' \
--user '<<CLIENT_ID>>:<<CLIENT_SECRET>>' \
--data '{
"grant_type": "client_credentials",
"scope": "sls:idn"
If the authentication is successful, as per the OAuth 2.1 RFC spec, the response is a JWT access token along with a JWT refresh token.
Below is an example of a response:
{
"access_token": "ACCESS_TOKEN_HERE",
"refresh_token": "REFRESH_TOKEN_HERE",
"token_type": "bearer",
"expires_in": 3600
}
access_token
- is the bearer token that is required with every request. This is a JWT token and contains basic user detailsrefresh_token
- is the refresh token that can be used to acquire another access_token token via https://guardian.beta.salussafety.io/token
An example of exchanging a refresh_token
for an access_token
is as follows:
curl -X POST --location '<<token_url>>' \
--header 'Content-Type: application/json' \
--user '<<client_id>>:<<client_secret>>' \
--data '{
"grant_type": "refresh_token",
"refresh_token": "REFRESH_TOKEN_HERE"
}'
A successful response from the refresh token request is identical to the access token response.
Authorization Code Grant
The authorization code grant protocol flow allows a specific user to be logged in against a client ID. This flow is useful if the Developer API is used for an interactive application that needs to enrich data in real time from the SALUS Platform. There are two types of clients that are supported: public
clients, and confidential
clients. Public clients are suitable for usage within single page apps, mobile apps, desktop apps, or other applications that can't be trusted to keep a secret. While confidential clients are clients that can be protected, for example REST APIs that are hosted and secured internally, or other components of this type.
Note: that public clients also use PKCE (Proof Key of Code Exchange) where another piece of data is used to verify that the caller's data was not tampered with before arriving at the Guardian IdP.
Further information about PKCE can be found via the protocol section of the RFC specification for PKCE. Short summary is as follows:
- Client creates a
code_verifier
-i_am_secret_with_good_entropy
- Client creates a
code_challenge
usingS256
method -base64_encode(sha256(ascii(code_verifier)))
- Client send
code_challenge
with authorization request, as in the example above - Server response with the
authorization_code
note, the server will never respond with thecode_challenge
here - Client sends
code_verifier
andauthorization_code
to thetoken
endpoint - Server verifies that the
base64_encode(sha256(ascii(code_verifier)))
is equal to thecode_challenge
previously received; iftrue
return theaccess_token
andrefresh_token
; otherwise returns an error.
An example of an authorize
request:
curl -X GET --get 'https://guardian.dev.salussafety.io/authorize' \
--data-urlencode 'client_id=client_333' \
--data-urlencode 'request_scope=idtoken+email' \
--data-urlencode 'redirect_uri=https://your-redirect-target.com/auth/callback' \
--data-urlencode 'code_challenge_method=S256' \
--data-urlencode 'code_challenge=B6VhlSf4UnqrkHFTVRAPHFD-7iPizqXA-vY3EW4-e-E' \
--data-urlencode 'response_type=code' \
--data-urlencode 'state=17bdc69a-cd4b-46fd-b7de-2b91a8c7f242' \
--data-urlencode 'scope=sls:idn' \
--header 'Accept: application/json'
Things of note above are the code_challenge_method
if omitted it will be defaulted to S256
. The code_challenge
which is the hashed value that the IdP will store for later when the token
endpoint is invoked. Finally, the scope
which is a custom scope that lets the IdP know that you would like to encode the users identity in the JWT token.
The Guardian IdP will respond with a 302 redirect, with a GET request to the specified redirect_uri
when that URI is part of the allowed redirect URIs configured in the IdP for the client specified.
And example of what the IdP will do below:
GET https://your-redirect-target.com/auth/callback
?state=966ae383-e5a1-49c0-bb30-b5cf554a6726
&session_state=966ae383-e5a1-49c0-bb30-b5cf554a6726
&code=cpvsWNeMOqEfmbznQL6UB_qgL9qCtvWiOzg63J7E3WmoRJ3OSn49NIyMp_DITFZC443Ln8J_ZnQoGKFpWpHNKcEAEpPm9t-4UTUgYg3SCPbvdXaSrLfUMX-LkcXSENzaXgBFQ-iC1wvqXUz4keHdSSHo776A-9tSl8NCgb2z
&scope=idtoken+email
Note: newlines and whitespace are added for readability here.
Then the client callback
endpoint will need to make a request to the token
endpoint with the code
specified, along with the original code_verifier
that was used to generate the code_challenge
in the authorize
request.
An example token
request with the code_verifier
and associated code
:
curl -X POST --location '<<token_url>>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"grant_type": "authorization_code",
"code": "CODE HERE",
"code_verifier": "i_am_secret_with_good_entropy",
"scope": "sls:idn"
}'
Example token
endpoint response given a valid authorization code and a valid verifier string.
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkFubU...nzEiEHoIWTB8VaVbg-v4lg",
"refresh_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkFu..._LmXzp-Ji8qCFbP0GE5IP8Y",
"token_type": "bearer",
"expires_in": 86400
}
Updated 9 months ago