Authentication

There are two types of authentication mechanisms for Clearance depending on whether a user or an integration is accessing the API.

User from a Web browser

When you are calling the Clearance API directly from a browser, you should always use OpenID Connect to authenticate the user and then use the bearer token in the API. The Clearance authentication will automatically leverage Azure Active Directory B2B and B2C to authenticate the users.

Request from a backend service

OAuth2: When another integration needs to communicate with Clearance, we use a combination of private/public keys to authenticate the service. The keys are available in the JSON Connection File generated after creating an integration account in Clearance.

616

The Clearance STS (Secure Token Services) is responsible for the generation of a JWT Bearer Token that can be used in the HTTP header of every REST API call. Bearer tokens have an expiration date and the caller is responsible for renewing the tokens before the expiration date.

The API client is responsible for renewing the access token before its expiration date. The response returned by the Token endpoint contains the information necessary to calculate the access token's expiration date.

548

To obtain an access token, you need to call the /token endpoint using the OAUTH2 protocol using the sub section RFC7523. To do that, you need to use the values contained in the JSON Connection File.

  • client_id
    the value should be @
  • grant_type
    the value should always be urn:ietf:params:oauth:grant-type:jwt-bearer as referenced by the RFC7523.
  • assertion
    the value should be a Json Web Token signed using the ServicePrincipalKey.

A typical call should look like this:

curl -X POST -d "client_id=<ServicePrincipalId>@<TenantId>&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<ENTER TOKEN ASSERTION HERE>" https://clearance-a-sts.geneteccloud.com/connect/token

To generate a token assertion, you just need to create a new Json Web Token and sign it with the key provided in the JSON Connection File :

string clientId = "<ServicePrincipalId>@<TenantId>";
var handler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
  Issuer = clientId,
  SigningCredentials = new SigningCredentials(
    new RsaSecurityKey(... ServicePrincipalKey from config.json ...), 	JsonWebKeySignatureAlgorithm.RS256)
};
var token = (JwtSecurityToken)handler.CreateToken(tokenDescriptor);
string tokenAssertion = handler.WriteToken(token);
import jwt = require("jsonwebtoken");
import fetch = require("node-fetch");
import pemjwk = require("pem-jwk");
import { OAuthTokenModel } from "./model/oauthtokenmodel";
import { TenantSettings } from "./model/tenantsettings";

export class OAuth2Client {

    private readonly m_tenantSettings: TenantSettings;

    constructor(tenantSettings: TenantSettings) {
        this.m_tenantSettings = tenantSettings;
    }

    public async getServicePrincipalAccessToken(): Promise<string> {

        const client_id: string = `${this.m_tenantSettings.ServicePrincipalId}@${this.m_tenantSettings.TenantId}`;

        const pemKey = pemjwk.jwk2pem(this.m_tenantSettings.ServicePrincipalKey);
        const now: number = new Date().valueOf() / 1000;
        const requestToken = jwt.sign({ iss: client_id, iat: now, exp: now + (60 * 60), nbf: now}, pemKey, { algorithm: "RS256"});
        const requestModel: OAuthTokenModel = {
            client_id,
            grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
            assertion: requestToken
        };

        const requestInfo: RequestInit = {
            method: "POST",
            body: JSON.stringify(requestModel),
            headers: {
                "Content-Type": "application/json"
            },
        };

        const response = await fetch(`${this.m_tenantSettings.SecurityTokenServiceBaseAddresses[0]}/token`, requestInfo);
        if (response.status === 200) {
            return (await response.json()).access_token;
        }
        throw response.text();
    }
}
import json
import time
from jwcrypto import jwk, jws, jwt
from jwcrypto.common import json_encode
import requests 
import datetime

with open('config.json') as config_json_file:
    data = json.load(config_json_file)
    now = int(time.time()) 
    client_id = data['ServicePrincipalId'] + '@' + data['TenantId']
    expkey = data['ServicePrincipalKey']
    key = jwk.JWK(**expkey)
    token = jwt.JWT(header={"alg": "RS256", "kid": key.key_id},
                    key=key,
                    claims={"iss": client_id, "sub": client_id, "iat": now, "exp": now + (60 * 60), "nbf": now})
    print(token.claims)
    token.make_signed_token(key)
    assertion = token.serialize(True)
    print(assertion)
    r = requests.post(url = data["SecurityTokenServiceBaseAddresses"][0] + "/token",
                      json = {
                        "client_id": client_id,
                        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
                        "assertion": assertion
                        }) 
    print r.json()["access_token"]

Once authenticated, the JWT Bearer Token should be included in the authorization header of every API request.
Example of GET API for an Evidence on the tenant “tenant123”

curl -X GET --header 'Accept: application/json' --header 'Authorization: Bearer eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhNTEyIiwia2lkIjoiNzFFODNEMDQ4NjIxMTg0RTMxOENEMDUxREEwMzhBRjQ2MjQ1QTkyMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiamRveW9uQGdlbmV0ZWMuY29tIiwiaHR0cDovL3NjaGVtYXMuZ2VuZXRlYy5jb20vd3MvMjAxNi8wMy9pZGVudGl0eS9jbGFpbXMvcHJpbWFyeWtpZCI6InVybjp1c2VyOmpkb3lvbmRlbW86amRveW9uQGdlbmV0ZWMuY29tOjMiLCJodHRwOi8vc2NoZW1hcy5nZW5ldGVjLmNvbS93cy8yMDE2LzAzL2lkZW50aXR5L2NsYWltcy9wcmltYXJ5aWQiOiIzIiwiaHR0cDovL3NjaGVtYXMuZ2VuZXRlYy5jb20vd3MvMjAxNi8wMy9pZGVudGl0eS9jbGFpbXMvcHJpbWFyeXR5cGUiOiJ1c2VyIiwiaHR0cDovL3NjaGVtYXMuZ2VuZXRlYy5jb20vd3MvMjAxNi8wMy9pZGVudGl0eS9jbGFpbXMvdGVuYW50aWQiOiJqZG95b25kZW1vIiwiaWF0IjoxNTA0NjM3NTg2LCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9naXZlbm5hbWUiOiJKb25hdGhhbiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL3N1cm5hbWUiOiJEb3lvbiIsImh0dHA6Ly9zY2hlbWFzLmdlbmV0ZWMuY29tL3dzLzIwMTYvMDMvaWRlbnRpdHkvY2xhaW1zL2dyb3Vwa2lkIjoidXJuOmdyb3VwOmpkb3lvbmRlbW86L1RlbmFudCBBZG1pbmlzdHJhdG9yOjEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsidGVuYW50YWRtaW4iLCJkZXZvcCJdLCJuYmYiOjE1MDQ2MzY2ODYsImV4cCI6MTUwNDY4MDc4NiwiaXNzIjoiaHR0cHM6Ly9jbGVhcmFuY2UtYS1zdHMuZ2VuZXRlY2Nsb3VkLmNvbS9jb25uZWN0IiwiYXVkIjoiY2xpZW50In0.lKs2Hqb7RAWH5o5A44YK1MzmGzCcoBmhMwtVzsUt5RtpIGqRU6SZD5NNRRXENoOg2GvfRAd6MDgk-2uplNgYSojOxp1YrPx5tAkYvFdcYCwJBw7c0RWM8doZ1gKdmHoqVZOGCGBB4PaJirlcr5z69VphCX_AX3-QX9ay9I1WiRlHdiry4v21z7gQ2UoeorsrMtbs_1EAqHS_1B_XJzL7uSW8nJv1pXf3LD247DMR-IH3sx-uAdQg_DU2LTuHm2a3MOo_1WLEot3SzRnASB2Bnj_3APPlUg80rnhfo8uJeEIEXubNVSygk5f0Ik0PuPlSBFX8f-B8l8nMtkAV3Xbo1w' 'https://clearance-a-ds.geneteccloud.com/api/v1/tenant/tenant123/evidence/30'