Authentication
Let's keep this secure.
IF Platform uses OpenID Connect (OIDC) and OAuth 2.0 protocol for authentication and authorization.
All entities need to be authenticated and authorised to be able to access any resource.
1. Principals
A principal is an entity, also known as an identity, that can be granted access to a resource. The IF Platform supports two types of principals: user accounts and service accounts.
User accounts represent a developer, administrator, or any other person who interacts with the IF Platform.
Service accounts represent non-human (machine type) users, such as an application server, and they are intended for connecting your system to the IF Platform.
2. Creating a Service Account
To be able to make API calls to the IF Platform you need a service account authorised to use the resources of your instance.
If you need an API connection, please request a service account with API access whilst your instance is being set up.
You will also need to create a key pair (public/private) and provide the public key certificate to the IF Team for your service account.
# generate a private key with the correct length
openssl genrsa -out private-key.pem 4096
# create a self-signed certificate (to be shared with IF)
openssl req -new -x509 -key private-key.pem -out certificate.pem -days 3600
Once the service account is created you will receive the client ID to represent your service account in OAuth 2.0 flows.
3. Authenticating a Service Account
The IF Platform uses OAuth 2.0 assertion flow to authenticate service accounts. The signed JWT in the flow shown below is called an assertion token.
3.1 Authentication endpoints
There are 2 endpoints involved in the authentication process for the IF Platform.
The first one is the OIDC issuer URI which is used as the audience (intended target) in assertion tokens. And the second one is the token endpoint where you can exchange the assertion token with the access token.
SANDBOX ENVIRONMENT:
OIDC Issuer: https://sandbox-account.integrated.finance/auth/realms/ifp
Token Endpoint: https://sandbox-account.integrated.finance/auth/realms/ifp/protocol/openid-connect/token
PRODUCTION ENVIRONMENT:
OIDC Issuer: https://account.integrated.finance/auth/realms/ifp
Token Endpoint: https://account.integrated.finance/auth/realms/ifp/protocol/openid-connect/token
3.2 Creating and signing the JWT
A JWT is composed of three parts:
- a header,
- a payload (claim set), and
- a signature.
The header and payload are JSON objects. These JSON objects are serialised to UTF-8 bytes, then encoded using the Base64URL encoding. This encoding provides resilience against encoding changes due to repeated encoding operations.
The header, payload, and signature are concatenated together with a period (.) character.
A JWT is composed as follows:
base64UrlEncode(header) + "." + base64UrlEncode(payload) + "." + base64UrlEncode(signature)
Where the signature is as follows:
RSASHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload) )
3.2.1 Forming the JWT header
The header consists of two fields that indicate the signing algorithm and the format of the assertion. Both fields are mandatory, and each field has only one value. As additional algorithms and formats are introduced, this header will change accordingly.
Service accounts rely on the RSA SHA-256 algorithm and the JWT token format. As a result, the JSON representation of the header is as follows:
{
"alg":"RS256",
"typ":"JWT"
}
3.2.2 Forming the JWT payload
The JWT payload contains information about the JWT, in this case the payload corresponds to the claim set which contains information relating to the service account being authenticated, the target and the lifetime of the token. Most of the fields are mandatory. Similar to the JWT header, the JWT payload is a JSON object and is used in the calculation of the signature.
Required claims
The required claims in the JWT payload are shown below. They may appear in any order in the payload.
Name | Description |
---|---|
jti | A unique identifier for the JWT. |
iss | Issuer of the token. When making access token request this value is always the client id of the service account. |
sub | Subject of the token. When making access token request this value is always the client id of the service account. |
aud | A descriptor of the intended target of the assertion. When making an access token request this value is always: https://sandbox-account.integrated.finance/auth/realms/ifp |
iat | The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970. |
exp | The expiration time of the assertion, specified as seconds since 00:00:00 UTC, January 1, 1970. This value has limit of maximum 10 minutes after the issuing time. |
The JSON representation of the required fields in a JWT payload is shown below for the sandbox environment:
{
"jti": "a-unique-id-for-the-token",
"iss": "[email protected]",
"sub": "[email protected]",
"aud": "https://[sandbox-]account.integrated.finance/auth/realms/ifp",
"iat": 1328550785,
"exp": 1328554385
}
Like the JWT header, the JWT payload should be serialized to UTF-8 and Base64URL encoded.
3.2.3 Computing the signature
JSON Web Signature (JWS) is the specification that guides the mechanics of generating the signature for the JWT. The input for the signature is the byte array of the following content:
base64UrlEncode(header) + "." + base64UrlEncode(payload)
The signing algorithm in the JWT header must be used when computing the signature. The only signing algorithm supported by the IF OAuth 2.0 Platform is RSA using SHA-256 hashing algorithm. This is expressed as RS256 in the “alg” field in the JWT header.
Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key you created. The output will be a byte array.
The signature must then be Base64url encoded. The header, payload and signature are concatenated together with a period (.) character. The result is the JWT.
Below you can find an example bash script to sign a JWT:
#!/usr/bin/env bash
set -e -o pipefail
# Your private key
PRIVATE_PEM=$( cat private-key.pem )
# Your client id
CLIENT_ID="[email protected]"
#Validity seconds for the JWT, maximum 10 minutes is allowed
VALIDITY=600 #10 minutes
#Audience
AUDIENCE="https://sandbox-account.integrated.finance/auth/realms/ifp"
#Scope
SCOPE="api"
#DATES
NOW=$( date +%s )
ISSUED_AT=${NOW}
EXPIRES_AT=$((${ISSUED_AT} + ${VALIDITY}))
JTI=$(uuidgen)
HEADER_RAW='{
"typ": "JWT",
"alg":"RS256"
}'
HEADER=$( echo "${HEADER_RAW}" | jq -c . | tr -d '\n' | openssl base64 -A | tr '/+' '_-' | tr -d '=' )
PAYLOAD_RAW='{
"jti":"'"${JTI}"'",
"iss":"'"${CLIENT_ID}"'",
"sub":"'"${CLIENT_ID}"'",
"aud":"'"${AUDIENCE}"'",
"iat":"'"${ISSUED_AT}"'",
"exp":"'"${EXPIRES_AT}"'"
}'
PAYLOAD=$( echo "${PAYLOAD_RAW}" | jq -c . | tr -d '\n' | openssl base64 -A | tr '/+' '_-' | tr -d '=' )
DATA="${HEADER}"."${PAYLOAD}"
SIGNATURE=$(openssl dgst -sha256 -sign <(echo -n "${PRIVATE_PEM}") <(echo -n "${DATA}") | openssl base64 -A | tr '/+' '_-' | tr -d '=' )
SIGNED_JWT="${DATA}"."${SIGNATURE}"
echo ${SIGNED_JWT} > signed.jwt
3.3 Making the access token request
After generating the signed JWT, your application can use it to request an access token. This access token request is a HTTPS POST request and the body is URL encoded.
The following parameters are required in the HTTPS POST request:
Name | Description |
---|---|
grant_type | Use the following: client_credentials |
client_assertion_type | Use the following: urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
client_assertion | The Signed JWT. |
Below you can find a raw dump of the HTTPS POST request and a curl example used in an access token request:
curl \
-d "grant_type=client_credentials" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.<payload>.<signature>" \
https://sandbox-account.integrated.finance/auth/realms/ifp/protocol/openid-connect/token
POST /oauth2/token HTTP/1.1
Host: sandbox-api.integrated.finance
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.<payload>.<signature>
Handling the response
If the JWT and access token request are properly formed, and the service account has permission to perform the operation, then the JSON response from the Authorization Server includes an access token. The following is an example response:
{
"access_token": "ey<rest-of-the-token>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "api"
}
Access tokens can be reused during the duration window specified by the expires_in value.
4. Calling IF Platform APIs
After your application obtains an access token, you can use the token to make calls to the IF Platform API on behalf of a given service account. To do this, include the access token in a request to the API by including an Authorization HTTP header Bearer value.
HTTP Example
A call to the get client endpoint (Clients API) using the Authorization: Bearer HTTP header might look like the following. Note that you need to specify your own access token:
curl -H "Authorization: Bearer <access_token>" https://sandbox-api.integrated.finance/v1/<instance-id>/clients
GET /v1/<instance-id>/clients
Host: sandbox-api.integrated.finance
Authorization: Bearer access_token
When access tokens expire
Access tokens issued by the IF OAuth 2.0 Authorization Server expire after the duration provided by the expires_in value. When an access token expires, then the application should generate another JWT, sign it and request another access token.
You should not create a new access token before each call to IF Platform. As good practice once you authenticate and get the access token you should cache and use it until it is close to expiry.
Updated about 1 year ago