tru.ID logo

Authentication

Docs
Reference

Authentication

tru.ID uses three methods of authentication. Basic Authentication with a client_id and a client_secret is used for managing access tokens. Bearer (Token) Authentication is used to authenticate all other APIs. Signed HTTP Message authentication is used with HTTP callbacks and webhooks made from the tru.ID platform to your application servers to enable you to verify the request origin.

All API requests must be made over HTTPS and API calls made over HTTP will fail.

This guide covers:

Basic Authentication

In the request the Authentication HTTP header value should be composed of Basic plus a Base64 value generated by concatenating a client_id, a colon (":") and a client_secret.

Authorization: Basic Base64Encode(concat({client_id}, ':', {client_secret}))

client_id and client_secret credentials are associated with either a Workspace (a container for usage and billing for one or more projects) or a Project (a container for configuration related to the usage of one or more products).

Workspace credentials are created upon creation of your tru.ID account and your default workspace (a workspace that is automatically created for you). They can be retrieved from the tru.ID Console]. The client_secret is only stored in browser localStorage and will be lost if you logout of the Console. You should store the client_secret securely. If required, you can reset your Workspace client_secret from the Console.

Project credentials are created upon creation of a new Project. Again, tru.ID does not store the client_secret so you should make sure you store it securely. You cannot reset your Project client_secret. Therefore, if you lose a Project client_secret you should create a new Project and associated credentials.

Basic client_id and client_secret authentication is used with:

Using Basic Authentication

The following example shows using Basic Authentication via a Base64 encoded header to create an access token.

Example

curl -H "Authorization: Basic Base64({client_id}:{client_secret})" \
-X POST -F 'grant_type=client_credentials' \
-F 'scope=phone_check' \
https://eu.api.tru.id/oauth2/v1/token

Basic client_id and client_secret authentication is used with:

Bearer (Token) Authentication

The tru.ID APIs expect the bearer token to be a OAuth2 Access Token. The access token should be within the Authorization HTTP header, prefixed with Bearer .

Authorization: Bearer {access_token}

An access token is created using a client_id and client_secret and the OAuth2 /token endpoint.

Access tokens are used with:

Creating Access Tokens

When creating an access token a grant_type of client_credentials should be used along with a scope. The scope defines the resources the access token enables access to. An access token can have multiple scopes by supplying scopes separated by a space within the scope parameter.

The scopes and associated resources are:

  • projects: /console/{version}/projects*
  • workspaces: /console/{version}/workspaces/*
  • phone_check: /phone_check/{version}/*

Examples

Create an access token with a scope of phone_check to access /phone_check/* resources.

curl -H "Authorization: Basic Base64({client_id}:{client_secret})" \
-X POST -F 'grant_type=client_credentials' \
-F 'scope=phone_check' \
https://eu.api.tru.id/oauth2/v1/token

Create an access token with a scope of projects and phone_check to access /console/{version}/projects* and /phone_check/{version}/* resources.

curl -H "Authorization: Basic Base64({client_id}:{client_secret})" \
-X POST -F 'grant_type=client_credentials' \
-F 'scope=projects phone_check' \
https://eu.api.tru.id/oauth2/v1/token

Using Access Tokens

The following example shows using access token authentication with to create a PhoneCheck.

Example

curl -X POST \
-H 'Authorization: Bearer IdyB_OyXbxf8-nsLfJtIYXvM5kY9-rjAejX8IvUisOo.H7McspB--9lRA5hdzzEM5GcsS0D87nTtvP6oGQtHFNI' \
-H 'Content-Type: application/json' \
-d '{"phone_number": "447700900000"}'
'https://eu.api.tru.id/phone_check/v1/checks'

Access tokens are used with:

Signed HTTP Messages for Callbacks & Webhooks

Callback and webhook requests are signed according to the http message signing RFC.

You verify if a request has been sent by the tru.ID platform ,and hasn't been tampered with, by validating a signature received in the request.

The signature verification process is as follows:

Signature Payload + Signature + Signing Key -> Verify Signature -> Valid | Invalid
  • Signature Payload - The payload used to create the signature. According to the RFC, it can be a combination of several parts of the request. For example, headers, request path, etc.
  • Signature - The result of signing the payload with the private part of the tru.ID signing key.
  • Signing Key - The public part of the key tru.ID used to sign the request.

Verifying the Signature

Public Signing Key

In order to verify a request signature you need to access the tru.ID public signing keys. They are exposed via an endpoint as a JSON Web Key Set (JWKS):

https://{data-residency}.api.tru.id/.well-known/jwks.json

This way, you always have access to the most recent set of signing keys. The JWKS is structured as follows:

{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "c05a90fb91000fe6b1b3b988127ac3d8756101ca",
"alg": "RS256",
"n": "ALyUy3g7f4Rt4-OxGOildEOj_FW5wjT7l0ZoumqbiCyWCsW5XC2J4QadAkcFaSFOGGwJCW_lGi-y8sCx67y5vG6t3l6pRQOxtZ7_4wZ69A4347fKe4vSekzQyZVBcBHEH12Ea2P5Juu_OQpVJoTcvdF6e1oyQXubJ70xNCkYdYvkUoMy8VViQpXZuKttP_z6gc6tck04sJKXqQG8WRPur2wpIu_jcfdUDOe9RRFiq_P90E9YnsweiszsHz2gthDbhDY9kZz-U4o8yLdwRPqBcJOp6ye6V5-9uZz9rFNMitHDuNOd_vtJCdaccJGQ0Re2lQplRWYtVOEDHmfCzmDigss="
}
]
}

There can be multiple keys inside the keys attribute. It is important to note the following attributes in a key:

  • kid - the key's unique identifier. One of these will match the keyId of the signature metadata recieved in the inbound request.
  • alg - the key's algorithm used to sign or verify requests. In this example it is RSA 256.

You should convert the JSON Web Key (JWK) into a PEM format, which should then be used to verify digital signatures. There are many libraries available that support this conversion.

Signature and Signature Payload

As per the RFC, the signature and corresponding metadata are in the Authorization header of the request. Here's an example of a signed PhoneCheck callback:

POST / HTTP/1.1
Host: enpcxr60rbv5h.x.pipedream.net
Authorization: Signature keyId="c05a90fb91000fe6b1b3b988127ac3d8756101ca",algorithm="rsa-sha256",headers="(request-target) host date x-4auth-callback digest",signature="PSNUgy/M7S2r62O6agIVvgopFyqLZv5UwpDu6ZBIqE2Me6kMy3vb8o+w8wVt+yVrLs8ZfJVL7LNnr5PcfNTxMvrfOp1pLuigvya42KCnN18RmfFubP54wQOnYb7j2UqS8CzJheSVzow8rOMqzZSMcXMUFvj1KQXETuRB0fJENw9RCvWMi59jg8TUD3S9jEWV0uw7d21j53+fdnaC7bIBF038A4NncLenbdTXSQX8R72CD4UAqA5/r/9VISoue/a2T3gC0MOueUOLC8AjLH864BV/2cDvyXz/9oTcm0SJ2CRaKdLaiolDx4LhaMGE4bC8xOSYXs2sGJwlsGJOIFCGGQ=="
Content-Type: application/json
Date: Fri, 18 Sep 2020 14:52:03 GMT
Digest: SHA-256=36206190f57d5a7dc5d8e2b9fa57f21ce0ecfd31f45eaaf200de2d5d6bffbc60
X-4auth-Callback: phone_check
Content-Length: 169
{"check_id":"c2b0ac55-9184-4bbe-9ce9-2147fcd9e63e","status":"COMPLETED","match":true,"charge_amount":1.0,"charge_currency":"API","created_at":"2020-09-18T14:51:54+0000"}

The signature metadata of this request, extracted from the Authorization header:

Signature keyId="c05a90fb91000fe6b1b3b988127ac3d8756101ca",algorithm="rsa-sha256",headers="(request-target) host date x-4auth-callback digest",signature="PSNUgy/M7S2r62O6agIVvgopFyqLZv5UwpDu6ZBIqE2Me6kMy3vb8o+w8wVt+yVrLs8ZfJVL7LNnr5PcfNTxMvrfOp1pLuigvya42KCnN18RmfFubP54wQOnYb7j2UqS8CzJheSVzow8rOMqzZSMcXMUFvj1KQXETuRB0fJENw9RCvWMi59jg8TUD3S9jEWV0uw7d21j53+fdnaC7bIBF038A4NncLenbdTXSQX8R72CD4UAqA5/r/9VISoue/a2T3gC0MOueUOLC8AjLH864BV/2cDvyXz/9oTcm0SJ2CRaKdLaiolDx4LhaMGE4bC8xOSYXs2sGJwlsGJOIFCGGQ=="

And the signature payload, extracted from the signature metadata field:

PSNUgy/M7S2r62O6agIVvgopFyqLZv5UwpDu6ZBIqE2Me6kMy3vb8o+w8wVt+yVrLs8ZfJVL7LNnr5PcfNTxMvrfOp1pLuigvya42KCnN18RmfFubP54wQOnYb7j2UqS8CzJheSVzow8rOMqzZSMcXMUFvj1KQXETuRB0fJENw9RCvWMi59jg8TUD3S9jEWV0uw7d21j53+fdnaC7bIBF038A4NncLenbdTXSQX8R72CD4UAqA5/r/9VISoue/a2T3gC0MOueUOLC8AjLH864BV/2cDvyXz/9oTcm0SJ2CRaKdLaiolDx4LhaMGE4bC8xOSYXs2sGJwlsGJOIFCGGQ==

In order to verify the signature, you first reconstruct the signature payload. The headers metadata field describes what the payload should look like. In our example it will have the following values:

  • (request-target) - the request method and the path and query of the effective request URI (examples)
  • host - the value of Host header
  • date - the value of Date header
  • x-4auth-callback - the value of x-4auth-callback header
  • digest - the value of Digest header. The value is the body contents hashed with the algoritm identified in the Signature header by algorithm={algoritm_value} and then Base64 encoded. For example, digest: SHA-256=hex(SHA256(Body)).

The reconstructed payload will look like this (the newlines are important):

(request-target): post /
host: enpcxr60rbv5h.x.pipedream.net
date: Fri, 18 Sep 2020 14:52:03 GMT
x-4auth-callback: phone_check
digest: SHA-256=36206190f57d5a7dc5d8e2b9fa57f21ce0ecfd31f45eaaf200de2d5d6bffbc60

The next step is identifying the key used to sign the request. The keyId metadata value should match a kid in the JWKS.

The final step is identifying the algorithm used to sign the request. The algorithm metadata value tells us it was rsa-sha256 so we can now fully verify the signature.

Example

The following Node.js example show how to handle the PhoneCheck callback, retrieve the tru.ID JWKS, parse the HTTP signature and verify that HTTP messages was signed, and thus the request made, by tru.

const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const util = require('util')
app.use(bodyParser.json())
const jwksClient = require('jwks-rsa')
const getSigningKey = util.promisify(keyClient.getSigningKey)
const httpSignature = require('http-signature')
const keyClient = jwksClient({
jwksUri: `${API_BASE_URL}/.well-known/jwks.json`,
})
app.post('/callback', async (req, res) => {
console.log('received callback', req.headers, req.body)
const parsed = httpSignature.parseRequest(req)
const keyId = parsed.keyId
const jwk = await getSigningKey(keyId)
const verified = httpSignature.verifySignature(parsed, jwk.getPublicKey())
if (!verified) {
res.sendStatus(400)
return
}
res.sendStatus(200)
})
app.listen(3000)

The libraries used in the above example are:

HTTP message signing and JWKS libraries are available in other programming languages.

HTTP message signing is used with:

tru.ID logo

Mobile authentication, reimagined.

Made with ❤️ across the 🌍

Platform

Docs

© 2021 4Auth Limited. All rights reserved. tru.ID is the trading name of 4Auth Limited.