Client credentials flow for OpenId Connect and OAuth 2.0
Overview
With the Client Credentials Flow (defined in RFC 6749, section 4.4) a Non Interactive Client (a CLI, a daemon, or a Service running on your backend), can directly ask Identify for an access_token by using its Client Credentials (Client Id and Client Secret) to authenticate. In this case the token represents the Non Interactive Client itself, instead of an end user.
How to implement the Client Credentials Grant
The Client's Grant Type property is set appropriately
The grant_type property must be set to client_credentials
Register the Client Id and Client Secret in Identify
From the Safewhere Admin applications list, you can create an OAuth2.0 application, then open its subtabs and update the following:
- On its connection tab:
- Client ID: Specifies the unique ID of the application. Client ID is case-sensitive.
- Client secret: Specifies the Client secret of the application. Client secret is case-sensitive.
- Token endpoint authentication method: Specifies the client authentication method to the token endpoint.
- Allowed Callback URIs: Specifies the redirect URL after successful authentication, e.g https://identifydomain/runtime/
- Application name: Specifies the name of the application
- Security token audiences: Specifies the recipients (usually in URI format) that issued access tokens are intended for. When the resource parameter is missing, an access token is issued with its 'aud' claim set to all configured audiences.
- On its security tab:
- JWS algorithm: Either RSASigning or HMACSymmetric.
- Symmetric signing key: Used to generate a HMAC Symmetric signing key; key can be 32-byte, 48-byte, or 64-byte. You can then either copy the key and paste it to the configuration or check the appropriate check box and click Select key to apply it.
- Allow client credentials flow: This setting must be True.
Security tab:
- JWS algorithm: either RSASigning or HMACSymmetric.
- Symmetric signing key: used to generate a HMAC Symmetric signing key; key can be 32-byte, 48-byte, or 64-byte. You can then either copy the key and paste it to the configuration or check the appropriate check box and click Select key to apply it.
- Allow client credentials flow: this setting must be True.
Ask for a token
To ask Identify for tokens for any of your authorized client applications, perform a POST operation to the token endpoint:
https://#identifydomain/runtime/oauth2/token.idp
URI parameters:
Parameter | Description |
---|---|
client_id | Your application's client ID |
client_secret | Your application's client secret |
grant_type | This must be "client_credentials" |
Here is sample:
The response contains a signed JSON Web Token, the token's type (which is Bearer), and in how much time it expires in Unix time (3600 seconds, which means 1 hour).
{"scope":"identify*empty","token_type":"Bearer","access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IkNVYjM4QjMzMjZ4TkI4RFRVN1JkZjhyWkJYNCIsIng1dCI6IkNVYjM4QjMzMjZ4TkI4RFRVN1JkZjhyWkJYNCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbGllbnRfY29ubmVjdF9zYW1wbGVfaWQiLCJuYW1lIjoiY2xpZW50X2Nvbm5lY3Rfc2FtcGxlX2lkIiwidG9rZW5fdXNhZ2UiOiJhY2Nlc3NfdG9rZW4iLCJqdGkiOiIzNjk2YTEwZC0xZGY0LTRiYWYtOThkYi02MDAzODg5NzkwYTkiLCJzY29wZSI6ImlkZW50aWZ5KmVtcHR5IiwiYXVkIjoiaHR0cHM6Ly9pZHBtYXN0ZXI2MC5zYWZld2hlcmUubG9jYWwvcnVudGltZSIsImF6cCI6ImNsaWVudF9jb25uZWN0X3NhbXBsZV9pZCIsImlhdCI6MTU5MDM3MDM5NCwibmJmIjoxNTkwMzcwMzk0LCJleHAiOjE1OTAzNzM5OTQsImlzcyI6Imh0dHBzOi8vaWRwbWFzdGVyNjAuc2FmZXdoZXJlLmxvY2FsL3J1bnRpbWUvb2F1dGgyIn0.fjLC8KNa25ka866T8O_2HDKVfhlqfZt1k0I5EEnywl6aYMftl3lsn83G2k6pGPkIe4GG08pkB-y_d42ocj57Mb7hrqFaYWx41y2Tab2nRosBRit416zo94U39iAKMDX7zuMtnkGRVuntw7YbH77RdG6ehkClBBJOfKWD6ndWiiP1yqf-lL3xf3zrENCy8UrCq8KAf_92-whBD7PJPzjDRV9DKxocse7wOIuUEg2p-cgfHzradaMADqadIcN-v99Vw_V9kCBuTXgzfmO0-KMKY5D37gNV9Z9BbTg0xA13zeVsiSgXZ_hhI-Q2NYPxM-gsrBHaRT8vwytOaG3VSBtJ-Q","expires_in":3600}
If you decode the access_token, you will see that it contains the following claims:
{
"sub": "client_connect_sample_id",
"name": "client_connect_sample_id",
"token_usage": "access_token",
"jti": "3696a10d-1df4-4baf-98db-6003889790a9",
"scope": "identify*empty",
"aud": "https://idpmaster60.safewhere.local/runtime",
"azp": "client_connect_sample_id",
"iat": 1590370394,
"nbf": 1590370394,
"exp": 1590373994,
"iss": "https://idpmaster60.safewhere.local/runtime/oauth2"
}
Tip: to decode a signed JSON Web Token you can use any JSON Web Token decoder tool such as https://www.rcfed.com/OAuth/JWTTokenDecode. Beware that some websites send your data to their servers though.
Claim Transformation Support
Claim Transformations are steps in the claim pipeline that transform the claim set attached to a token. The way in which this transformation is done depends on the type of Claim Transformation object. You can set up claim pipeline transformation rules that can be attached to any of your authorized client applications.
Given that you have a JWT token like below:
{
"sub": "client_connect_sample_id",
"name": "client_connect_sample_id",
"token_usage": "access_token",
"jti": "3696a10d-1df4-4baf-98db-6003889790a9",
"scope": "identify*empty",
"aud": "https://idpmaster60.safewhere.local/runtime",
"azp": "client_connect_sample_id",
"iat": 1590370394,
"nbf": 1590370394,
"exp": 1590373994,
"iss": "https://idpmaster60.safewhere.local/runtime/oauth2"
}
Because the Client credentials flow has no user context, only certain claims transformations can be used.
Add Value claim transformation
You can set up an Add Value claim transformation.
Then attach the Add Value claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"sub": "client_connect_sample_id",
"role": [
"ClaimAdmin",
"ConnectionAdmin",
"Identify Service",
"UserAdmin"
],
"urn:identify:rest-api:role": "Observer",
"company": "Safewhere",
"Title": "Developer",
"name": "client_connect_sample_id",
"token_usage": "access_token",
"jti": "3696a10d-1df4-4baf-98db-6003889790a9",
"scope": "identify*empty",
"aud": "https://idpmaster60.safewhere.local/runtime",
"azp": "client_connect_sample_id",
"iat": 1590370394,
"nbf": 1590370394,
"exp": 1590373994,
"iss": "https://idpmaster60.safewhere.local/runtime/oauth2"
}
Scripting claim transformation
Set up a Scripting claim transformation.
Attach the Scripting claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"Country": "Denmark",
"sub": "client_connect_sample_id",
"role": [
"ConnectionAdmin",
"Identify Service",
"UserAdmin"
],
"company": "Safewhere",
"Title": "Developer",
"name": "client_connect_sample_id",
"token_usage": "access_token",
"jti": "3696a10d-1df4-4baf-98db-6003889790a9",
"scope": "identify*empty",
"aud": "https://idpmaster60.safewhere.local/runtime",
"azp": "client_connect_sample_id",
"iat": 1590370394,
"nbf": 1590370394,
"exp": 1590373994,
"iss": "https://idpmaster60.safewhere.local/runtime/oauth2"
}
Mapping claim transformation
Before trying out the Mapping claim transformation, you can use the "Add Value" claim transformation to add some claim values first.
Set up a Mapping claim transformation.
Attach the Mapping claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"sub": "client id _ WeXKAjwbb0s=",
"role": [
"ClaimAdmin",
"ConnectionAdmin",
"Identify Service",
"UserAdmin"
],
"Title": "Developer",
"company": "Safewhere VN",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "da7a00d5-d468-4923-a54b-e0b942b806c3",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597822711,
"nbf": 1597822711,
"exp": 1597826343,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}
Claim Filter claim transformation
Set up a Claim Filter claim transformation.
Attach the Claim Filter claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"role": [
"ConnectionAdmin",
"UserAdmin"
],
"Title": "Developer",
"sub": "client id _ WeXKAjwbb0s=",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "efd4b367-225c-42d9-abe4-e7d679272a77",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597825517,
"nbf": 1597825517,
"exp": 1597829117,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}
External Claims claim transformation
Set up an External Claims claim transformation.
Attach the External Claims claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"automation_test": "login-logout-automation-test",
"sub": "client id _ WeXKAjwbb0s=",
"role": [
"ClaimAdmin",
"ConnectionAdmin",
"UserAdmin",
"Identify Service"
],
"urn:identify:rest-api:role": "Observer",
"company": "Safewhere",
"Title": "Developer",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "a2c5ff8a-99fd-4361-8423-b5dd6382f7d8",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597826289,
"nbf": 1597826289,
"exp": 1597829904,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}
Remove Duplicate claim transformation
Before trying out the Remove Duplicate claim transformation, you can add some duplicate values to a claim type (e.g: "title") by using the "Add Value" claim transformation
Set up a Remove Duplicate claim transformation.
Attach the Remove Duplicate claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"sub": "client id _ WeXKAjwbb0s=",
"role": [
"ClaimAdmin",
"ConnectionAdmin",
"UserAdmin",
"Identify Service"
],
"urn:identify:rest-api:role": "Observer",
"company": "Safewhere",
"title": "Developer",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "62a99deb-29e2-46b9-8751-b68c277bd80b",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597830342,
"nbf": 1597830342,
"exp": 1597833942,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}
Exclude Identify Claims claim transformation
Set up an Exclude Identify Claims claim transformation.
Attach the Exclude Identify Claims claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"role": [
"ClaimAdmin",
"UserAdmin",
"Identify Service"
],
"company": "Safewhere",
"sub": "client id _ WeXKAjwbb0s=",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "b60cbcf2-4cdc-4dee-81be-0f77c0cfc48f",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597831669,
"nbf": 1597831669,
"exp": 1597835281,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}
"Exclude Passthrough Claims" claim transformation
Set up an Exclude Passthrough Claims claim transformation.
Attach the Exclude Passthrough Claims claim transformation to your OAuth 2.0 application.
Finally, send a request to get an access_token
and check its content:
{
"role": [
"ConnectionAdmin",
"UserAdmin"
],
"sub": "client id _ WeXKAjwbb0s=",
"name": "client id _ WeXKAjwbb0s=",
"token_usage": "access_token",
"jti": "dd484ea8-734f-4ecd-bf4e-503a563b6af3",
"scope": "identify*empty",
"aud": "https://identify01.identify.safewhere.com/runtime/",
"azp": "client id _ WeXKAjwbb0s=",
"iat": 1597832154,
"nbf": 1597832154,
"exp": 1597835764,
"iss": "https://identify01.identify.safewhere.com/runtime/oauth2"
}