OAuth 2.0 and JSON Web Token (JWT) are the authentication methods used by Genetec ClearID™ to implement machine-to-machine authentication. The ClearID Secure Token Service (STS) is responsible for authenticating the client machine through OAuth and returning a JWT bearer token once authenticated, which allows users to access the API.
To use the ClearID API, the client application must authenticate with the token endpoint of the Secure Token Service (STS). This service returns an access token that remains valid for one hour. The access token can be used to access the API Endpoints.
ClearID uses JWTs as Authorization Grants as detailed in RFC 7523 section 2.1.
How to authenticate with the Token Endpoint
To authenticate, a POST request must be sent to the Secure Token Service (STS) endpoint /connect/token
.
The token endpoints expects the POST Method to have three parameters in the HTTP body:
client_id: This information is contained in the JSON file downloaded from ClearID.
grant_type: It should always be
urn:ietf:params:oauth:grant-type:jwt-bearer
.assertion: it is a JWT in base 64 see the details later in this article.
The context type is always: application/x-www-form-urlencoded
.
Example of POST data sent for /connect/token
:
client_id = 6625221f-4e66-4bc8-8305-cb8cbd87b21f:cleariddemos
grant_type = urn:ietf:params:oauth:grant-type:jwt-bearer
assertion = eyJhbGciOiJSUzUxMiIsImtpZCI6IjY2MjUyMjFmLTRlNjYtNGJjOC04MzA1LWNiOGNiZDg3YjIxZjpjbGVhcmlkZGVtb3MiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2NjI1MjIxZi00ZTY2LTRiYzgtODMwNS1jYjhjYmQ4N2IyMWY6Y2xlYXJpZGRlbW9zIiwianRpIjoiYzBkYTYyNWY0ZjYxNDNiNmFiOGIwMWRmYjJkNzU1YjciLCJuYmYiOjE2Mzk4NDM4OTQsImV4cCI6MTYzOTg0NzQ5NCwiaWF0IjoxNjM5ODQzODk0LCJpc3MiOiI2NjI1MjIxZi00ZTY2LTRiYzgtODMwNS1jYjhjYmQ4N2IyMWY6Y2xlYXJpZGRlbW9zIiwiYXVkIjoiaWFtcy1zdHMifQ.XU1HJDxE2mBjPDtHl65BUQAcWf42LXJw-pcUL5kQjKlGuD_a5H20Chq6F5K7Ov-XfM5sYpKRj4gDczVRDhVJqblAa5h54E13iuobFvnDZDQViTwrsPHvGOtSifDl3qw1hhljaYDvX7PAOvnSYG3hHAOvNpFvLxbqlAE8PgAx2v1Z-PCu0jJfa9djLcHWFINL3xiYo0VF-Jex2-N8nx8-xT5mFOIlO6D5Zp74frR5Anc7JP1BvPfYNgLmNSCir7ogT-KwFVxS8QedMDuSV038BRVTDOQ-NH-FHHrlNKIirgeWgoYscTXtD9j15nXj-bEgQFMCg-ZxxUtZ67OCJyzmsg
Since it is URL encoded, the resulting HTTPS request looks like this:
Sample request
POST /connect/token
Host: sts.clearid.io
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 897
client_id=6625221f%2D4e66%2D4bc8%2D8305%2Dcb8cbd87b21f%3Acleariddemos
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant%2Dtype%3Ajwt%2Dbearer&
assertion=eyJhbGciOiJSUzUxMiIsImtpZCI6IjY2MjUyMjFmLTRlNjYtNGJjOC04MzA1LWNiOGNiZDg3YjIxZjpjbGVhcmlkZGVtb3MiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2NjI1MjIxZi00ZTY2LTRiYzgtODMwNS1jYjhjYmQ4N2IyMWY6Y2xlYXJpZGRlbW9zIiwianRpIjoiYzBkYTYyNWY0ZjYxNDNiNmFiOGIwMWRmYjJkNzU1YjciLCJuYmYiOjE2Mzk4NDM4OTQsImV4cCI6MTYzOTg0NzQ5NCwiaWF0IjoxNjM5ODQzODk0LCJpc3MiOiI2NjI1MjIxZi00ZTY2LTRiYzgtODMwNS1jYjhjYmQ4N2IyMWY6Y2xlYXJpZGRlbW9zIiwiYXVkIjoiaWFtcy1zdHMifQ.XU1HJDxE2mBjPDtHl65BUQAcWf42LXJw-pcUL5kQjKlGuD_a5H20Chq6F5K7Ov-XfM5sYpKRj4gDczVRDhVJqblAa5h54E13iuobFvnDZDQViTwrsPHvGOtSifDl3qw1hhljaYDvX7PAOvnSYG3hHAOvNpFvLxbqlAE8PgAx2v1Z-PCu0jJfa9djLcHWFINL3xiYo0VF-Jex2-N8nx8-xT5mFOIlO6D5Zp74frR5Anc7JP1BvPfYNgLmNSCir7ogT-KwFVxS8QedMDuSV038BRVTDOQ-NH-FHHrlNKIirgeWgoYscTXtD9j15nXj-bEgQFMCg-ZxxUtZ67OCJyzmsg
The STS base address is different depending on the environment that you have. Currently, there are two different base addresses. In the future, there may be more addresses added.
Production STS: https://sts.clearid.io
Dev STS: https://sts-demo.clearid.io
Do not hardcode it in your code. You can find the base URL in the JSON file downloaded from ClearID. See the next section to find out more.
If the authentication succeeds, the Secure Token Service (STS) returns an access token of the type "Bearer".
The response should look like the example below.
The expires_in key contains the number of seconds before you must request a new token.
NB: The longest token that you can request for ClearID is 60 minutes.
Successful response from /connect/token
{
"access_token": "eyJhbGciOiJSUzUxMiIsImtpZCI6IjIwMTgtMDEtMjYtaWFtcy1zaWduaW5nLWNyZWRlbnRpYWwiLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE2NDAwMzAxMjIsImV4cCI6MTY0MDAzMzcyMiwiaXNzIjoiaHR0cHM6Ly9zdHMtZGVtby5jbGVhcmlkLmlvIiwiY2xpZW50X2lkIjoiNjYyNTIyMWYtNGU2Ni00YmM4LTgzMDUtY2I4Y2JkODdiMjFmOmNsZWFyaWRkZW1vcyIsInN1YiI6IjY2MjUyMjFmLTRlNjYtNGJjOC04MzA1LWNiOGNiZDg3YjIxZiIsImF1dGhfdGltZSI6MTY0MDAzMDEyMiwiaWRwIjoibG9jYWwiLCJlbWFpbCI6IjY2MjUyMjFmLTRlNjYtNGJjOC04MzA1LWNiOGNiZDg3YjIxZiIsInJvbGUiOiJTZXJ2aWNlIiwiYWNjb3VudF9pZCI6ImNsZWFyaWRkZW1vcyIsImNsZWFyaWRkZW1vc19zdGF0ZSI6IkFjdGl2ZSIsImNsZWFyaWRkZW1vc19yb2xlIjoiYWRtaW4iLCJjbGVhcmlkZGVtb3NfaXNfZGVsZWdhdGUiOmZhbHNlLCJqdGkiOiIwMDUwRjA3ODk2MjRCNjlGREM5NjFEMTA4QkQ1RDc3MiIsImlhdCI6MTY0MDAzMDEyMiwic2NvcGUiOlsiaWFtcy1hbGwtcGVybWlzc2lvbnMtZGVsZWdhdGVkIiwiaWFtcy1hcGkiLCJpYW1zLXJvbGVzIiwib3BlbmlkIl0sImFtciI6WyJhc3NlcnRpb24iXX0.kO3QzR9KP8pQxu4juBtpotk1Gdfpt095f9V8Xx75tW3ZzjK5kNB8ZEjJKe34p8oe_YAou_6xFL_lrIc3L0X4I9qJaV-8RDnCzyw2hWw2Vh4TGpwNgfM-BE6e7NZzfvWsmByYCrQQqLNqtKyPirjNgYeO_dLtGdfSbHpBayV7r-nuurGNAc1I0Y5wtoo6vbuKtmXCYl59mD22kYE4o2ucVtt94P8RkoXPD6eTY0TNB-C1e1IQyGrMdlqcmff9TiUhrAIwSWmxr4E-4JlYdVqahZoLSg2ZnmpnSCAnQbCy568SEa-is9WbSO2LNhsKBW7_URa7rQ2-oDyC8h2pCDFXhg",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "iams-all-permissions-delegated iams-api iams-roles openid"
}
How to find the STS base address, client_id, accountid, kid, key to sign
To build generic code that can work with any ClearID customer, the code you develop should not contain a hardcoded base URL, account ID, or cryptographic keys.
The administrator of a ClearID account can download a JSON file that your integration can use with a configuration file. That JSON file can be downloaded by any administrator of the ClearID account in Administration > Automation.
After creating a Service User on the automation page, you can then generate a new key. You will then be able to download the authentication, which is a useful JSON document.
Each time you click Generate Key, the previous key associated with this Service User becomes invalid and can no longer be used to authenticate.
The JSON downloaded from ClearID should be securely stored. It contains the credentials of a service account (administrative level) to integrate with ClearID.
Each customer you support provides this JSON file to allow your integration to work.
The JSON file contains:
accountid: This accountid is required in every API call that you make to ClearID.
*clientid: This is required in the authentication process. It functions similarly to a username, while the password acts as a signature using a private key.
key: This is the private key required to sign the JWT token during the authentication process. It is a serialized JSON Web Key.
stsUrl: This is the base URL of the service implementing the OAuth
/connect/token
endpoint required to authentication.identityServiceUrl: This is the base URL of the Identity Service API. This is the API that 90% of the ClearID integrations are using.
Other well-known API endpoints:
principalServiceUrl
,roleServiceUrl
. See the API Endpoints for more details.
{
"accountId": "adwe23cse",
"clientId": "6c0daac0-ad9c-49b0-bccf-e64dd3fae87a:adwe23cse",
"identityRequestServiceUrl": "https://api-demo.clearid.io/identityrequest",
"identityServiceUrl": "https://identityservice-demo.clearid.io",
"key": {
"kid": "6c0daac0-ad9c-49b0-bccf-e64dd3fae87a:cleariddemos",
"keyType": "RSA",
"algorithm": "RS512",
"exponent": "AQAB",
"modulus": "ui0UqPfRKKKnUZ1699I2WPb3gtoc4Echc0D25L6nDFRz1gshxY9GWxxmhqObglK3V-eu8vwI5AVaFQsLpVzz0JzKEN4-b1cZwzCPyZiMacs7XFucQqcULxYL1xN0PVGLAGHOUipctG6DY1DiZCS0G-qFU_pL92IJ9pDI5gpk2mvagxIzn8sP1ojesmWKTYTshBIDMyklhB_k_2mVrmv_qlUi-AkPmlxMgpK2DLQN-V0xxg6wFXqWkhZdYj2f7DV-7_YMl_u9GdbWa3IGKRwIm0HriCBPhzVdyFyJiEr7B7kScvCt_RKRs5kPRGobqTnjV2lCtppjbMUwTFLPli5b6Q",
"d": "PRy8KeTC9wRBSRSY_001Asn6oCzJisM-ky8RfC-q9Oyp42pfCRMJRLITY4HD86kEPuoxrtgVcQfitIKeLYdQDzvQRm41b2XXco93u3SELtwD3cLCjcx7XyNs-ooLv28LYjI4wBbgvGeEYG72CWpU5s76OgEwu4EmhRWspHpn9ZwdrdtcEph0DiXvZE9Cf10g6O7MPV6ZFYfXVFbj8bzftEGDgr2M8Mm-rK51k-FGYuBzgL9ExCAFoMZej4PwrFR5609dcDY2A3py7vFuRk9mCk2VBbkuxE2drH0vyxSRQhLTfF_JEK2y1lyizwABdVfUA4fCmGqWuM-VKWzhwRg34w",
"dp": "HH_CEcH-yN2XNjh_TAvZ2g6Jeu9xq_lYAD5al2UhKxyfZtqPG1ffr8rHTzOJRAg7u3twa3kW10ymNkjhk6qiXGyXgpASDmONPDoC9zsyEt42dGbpCQTQeSDYM2pKiWX81Y5U53oyVz_wtQJh7ZXlXSPeSwVNnQD6wEg5z_wtfW8",
"dq": "E-iPGV5XzlH1uwpc8tsuXdfky3XVP77dduZMWiGiLtPxJSKSulS61151ZmgRlI2Yzx6Kt2gx2xRkl5yu1g-VA_axI_a4loxbUz01t4s9eSKYHhgEy89yD1-pugpDrgdSHfE1zdXBYVG2563OVJv5B9XwsUBi9tot_bJBhKKnEzk",
"inverseQ": "I_vh5RefyV6Ki4dl6-aJw6fbO6iDIVj6h5BOnn_WRehhhLY17um6FJSp3bvzlwWDIfPdGJv07XMtWBrsqOzX1QbmnvfDo2EYj5HrSgjIdII8FXqM1IKIl7DChtfWKApA6pakjPFU0JF4aUCVm-g0n6USw2WSUuKSBS00L565a-c",
"p": "u3fHgoHGKCU1XSMc3pmnZqlr4UrdhygO11V1IytcsDYghDnQGhR60Fj8EXFng6yjnnCyMWy5UqXf9OBdpZwzd_6pg60szF5Xt5-SQzjyt5_U5kNOfyKmTAo1m0m3yfN3fv1DMA1ofNV5OmGqVPGBtauNKnatFwMneW8vXIcXWMs",
"q": "_jxopq5zKcpUDZKn3hYCcgu0WFMKdFVCu1laaNqA68DySTbdU5O2YKN0ke5wxEx9JHtnDk_gPPgzrds1aXlFA_nenG0r9d74mN5TpENLCvpGqzSfBM0DVUlIg-PzpMOMiKVmT_2RA4viI8BzDRWhnJTgohL3YdPyBsviA8y0q5s"
},
"principalServiceUrl": "https://principalservice-demo.clearid.io",
"roleServiceUrl": "https://roleservice-demo.clearid.io",
"stsUrl": "https://sts-demo.clearid.io",
"teamServiceUrl": "https://roleservice-demo.clearid.io",
"webhooksServiceUrl": "https://api-demo.clearid.io/webhooks"
}
How to create the assertion token
The assertion token is a JWT token that contains three standard sections:
The header defining the format of the signature.
The payload that contains details about your request.
The signature that proves your identity. The signature is generated by using the key provided in the JSON file.
JWT Assertion Token before it gets encoded in Base64
{
alg: "RS512",
kid: "6c0daac0-ad9c-49b0-bccf-e64dd3fae87a:adwe23cse",
typ: "JWT"
}.
{
sub: "6c0daac0-ad9c-49b0-bccf-e64dd3fae87a:adwe23cse",
jti: "9f0ad933bebe496f8483da730e519e67",
nbf: 1637789750,
exp: 1637793350,
iat: 1637789750,
iss: "6c0daac0-ad9c-49b0-bccf-e64dd3fae87a:adwe23cse",
aud: "iams-sts"
}.
[signature]
The complete definition of the JWT claims can be found in the RFC 7519
The header of this JWT contains:
alg is the value found in key:algorithm of the JSON file
kid is the value found in key:kid of the JSON file
typ is always JWT
The payload contains standard JWT claim fields:
sub is the subject and it should be the value of
clientId
in the JSON file.jti the JWT ID is a unique identifier of 32 digits that you should generate from a UUID generator to make sure it is unique.
nbf means "Not before". It refers to the NumericDate when the token starts to be valid.
exp is the expiration time of the token as a NumericDate. The maximum duration allowed by ClearID is 60 minutes. This value should be smaller or equal to nbf + 3600.
iat is the time that the token is issued. It is the current time in NumericDate.
iss is the issuer of the JWT in our context. It is the value of
clientId
in the JSON file.aud is the audience for this claim, in our context. It is always
iams-sts
for ClearID.
NB: NumericDate is a standard format for the number of seconds since EPOCH in UTC.
The JSON file contains a serialized JSON Web Key that should be used to sign the assertion token required to authenticate.
Refer to our Code samples for authentication examples in different languages (C#, Java and Javascript).
To generate a signed JWT, use a standard framework.
In .NET use the namespace Microsoft.IdentityModel.Tokens
.
How to generate JWT assertion token in C#
private string GetAssertion(string clientId, string serializedJsonWebKey)
{
var jsonWebKey = new JsonWebKey(serializedJsonWebKey);
var signingCredentials = new SigningCredentials(jsonWebKey, "RS512")
{
//Needed to automatically set the kid in the JWT header:
Key = { KeyId = jsonWebKey.Kid }
};
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = clientId,
Audience = "iams-sts",
SigningCredentials = signingCredentials,
Expires = now.AddHours(1), // IMPORTANT: maximum token lifetime allowed by the STS is 1 hour
IssuedAt = now,
Subject = new ClaimsIdentity(new[] { new Claim(JwtRegisteredClaimNames.Sub, clientId), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")) })
};
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateJwtSecurityToken(tokenDescriptor);
var assertion = handler.WriteToken(token);
return assertion;
}