OIDC claims
This plugin extension point is invoked when issuing an ID token or during a
request to the /userinfo OIDC endpoint. Use this script to retrieve
claim values based on an issued access token.
- Sample scripts
-
-
OIDC Claims Script (Legacy JavaScript)
-
OIDC Claims Script (Groovy)
-
- Script bindings
- Java interface
-
org.forgerock.oauth2.core.plugins.UserInfoClaimsPluginSample Java code
/* * Copyright 2021-2025 Ping Identity Corporation. All Rights Reserved * * This code is to be used exclusively in connection with Ping Identity * Corporation software or services. Ping Identity Corporation only offers * such software or services to legal entities who have entered into a * binding license agreement with Ping Identity Corporation. */ package org.forgerock.openam.examples; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.forgerock.oauth2.core.AccessToken; import org.forgerock.oauth2.core.ClientRegistration; import org.forgerock.oauth2.core.OAuth2Request; import org.forgerock.oauth2.core.UserInfoClaims; import org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin; /** * Custom implementation of the User Info Claims * plugin interface {@link org.forgerock.oauth2.core.plugins.UserInfoClaimsPlugin} * * <li> * The {@code getUserInfo} method * populates scope values and sets the resource owner ID to return. * </li> * */ public class CustomUserInfoClaimsPlugin implements UserInfoClaimsPlugin { @Override public UserInfoClaims getUserInfo(ClientRegistration clientRegistration, AccessToken token, OAuth2Request request) { Map<String, Object> response = mapScopes(token); response.put("sub", token.getResourceOwnerId()); UserInfoClaims userInfoClaims = new UserInfoClaims(response, null); return userInfoClaims; } /** * Set read and write permissions according to scope. * * @param token The access token presented for validation. * @return The map of read and write permissions, * with permissions set to {@code true} or {@code false}, * as appropriate. */ private Map<String, Object> mapScopes(AccessToken token) { Set<String> scopes = token.getScope(); Map<String, Object> map = new HashMap<String, Object>(); final String[] permissions = {"read", "write"}; for (String scope : permissions) { if (scopes.contains(scope)) { map.put(scope, true); } else { map.put(scope, false); } } return map; } }
Examples using legacy scripts
Refer to the following sections for example use cases:
|
If you are using the Ping Advanced Identity Software, you can add a |
Add a custom claim to the profile scope
Complete the following steps to implement an example OIDC claims script that adds a custom claim to the profile scope:
This example adds the custom claim to the access token and uses the /oauth2/userinfo endpoint to inspect the custom claim values.
Create the script
This task describes how to modify the default script to map a custom claim.
This example uses a legacy script. Find a next-generation example here.
-
In the AM admin UI, go to Realms > realm name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Groovy
-
JavaScript
-
Add a new claim to the script. As a simple example, insert
myTestNameafter thenameclaim in theclaimAttributessection as follows:claimAttributes = [ "email": userProfileClaimResolver.curry("mail"), ... "name": userProfileClaimResolver.curry("cn"), "myTestName": userProfileClaimResolver.curry("cn") ] -
Add the new claim to the
profilescope in the claims map:scopeClaimsMap = [ "email": [ "email" ], ... "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name", "myTestName" ]
-
Add the new
myTestNameclaim to theprofilescope in theutils.setScopeClaimsMapsection:utils.setScopeClaimsMap({ profile: [ 'name', 'family_name', 'given_name', 'zoneinfo', 'locale', 'myTestName' ], email: ['email'], -
Add the new claim to the script. For example, insert
myTestNameafter thephone_numberclaim in theutils.setClaimResolverssection as follows:utils.setClaimResolvers({ ... phone_number: utils.getUserProfileClaimResolver('telephonenumber'), myTestName: utils.getUserProfileClaimResolver('cn') });
-
-
Save your changes.
The default OIDC claims script is now amended to retrieve a custom claim for the profile scope.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofile
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
Save your changes.
AM is now prepared for you to try this sample user info claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMTCopy the value of the
access_tokenappended to the redirection URI in the response. You’ll need this value in the next step. -
-
Call the /oauth2/userinfo endpoint to inspect the custom claim values, including the access token obtained from the previous request.
For example:
$ curl \ --request GET \ --header "Authorization: Bearer az91IvnIQ-uP3Eqw5QqaXXY_DCo" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/userinfo" { "given_name":"Babs", "family_name":"Jensen", "name":"bjensen", "myTestName":"bjensen", "sub":"(usr!bjensen)", "subname":"bjensen" }Verify the response contains the custom claim added by the script (
myTestNamein this example).
Add a custom claim to a custom scope
Complete the following steps to implement an example OIDC claims script that adds a custom claim to a custom scope:
This example adds the custom claim to the ID token and uses the /oauth2/idtokeninfo endpoint to inspect the custom claim values.
Create the script
This task describes how to modify the default script to map a custom claim.
| If you want the custom claim to use a custom attribute instead of an existing one, make sure you have added the custom user profile attribute first. |
This example uses a legacy script. Find a next-generation example here.
-
In the AM admin UI, go to Realms > realm name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Groovy
-
JavaScript
-
Add a new claim to the script. As a simple example, insert
myCustomAttrafter thenameclaim in theclaimAttributessection as follows:claimAttributes = [ "email": userProfileClaimResolver.curry("mail"), ... "name": userProfileClaimResolver.curry("cn"), "myCustomAttr": userProfileClaimResolver.curry("employeenumber") ] -
Add the new claim to a new
customscope in the claims map:scopeClaimsMap = [ "email": [ "email" ], ... "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name" ], "custom": [ "myCustomAttr" ]
-
Add the new
myCustomAttrclaim to a newcustomscope in theutils.setScopeClaimsMapsection:utils.setScopeClaimsMap({ ... phone: ['phone_number'], custom: ['myCustomAttr'] -
Add the new claim to the script. For example, insert
myCustomAttrafter thephone_numberclaim in theutils.setClaimResolverssection as follows:utils.setClaimResolvers({ ... phone_number: utils.getUserProfileClaimResolver('telephonenumber'), myCustomAttr: utils.getUserProfileClaimResolver('employeenumber') });
-
-
Save your changes.
The default OIDC claims script is now amended to retrieve a custom claim for the custom scope.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
-
Switch to the Advanced OpenID Connect tab to always return scope-derived claims in the ID token.
-
Select Always Return Claims in ID Tokens.
This option is disabled by default because of the security concerns of returning claims that may contain sensitive user information. Learn more in Request claims in ID tokens. -
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofilecustom
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
Save your changes.
AM is now prepared for you to try this sample OIDC claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile custom -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile custom" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMTCopy the value of the
id_tokenappended to the redirection URI in the response. You’ll need this value in the next step. -
-
Call the /oauth2/idtokeninfo endpoint to inspect the custom claim values, including the ID token obtained from the previous request.
For example:
$ curl \ --request POST \ --user myClient:mySecret \ --data 'id_token=eyJ0eXA…7QdQpg' \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/idtokeninfo" { "at_hash":"PZg5xZsIlFtRSfg8MAWhWg", "sub":"(usr!bjensen)", "auditTrackingId":"2e5c7611-4a61-4001-8739-f714d43e9da2-881454", "subname":"bjensen", "iss":"https://am.example.com:8443/am/oauth2", "tokenName":"id_token", "given_name":"Babs", "nonce":"abc123", "sid":"+buKyDp+Fbc0/Rkd0OqsfdKy7ZY0nWvcsEetikX+eTc=", "myCustomAttr":"1234", "aud":"myClient", "acr":"0", "org.forgerock.openidconnect.ops":"gkQOcZ1F3ZFdYPd6TiGIgr6scH0", "s_hash":"bKE9UspwyIPg8LsQHkJaiQ", "azp":"myClient", "auth_time":1676360741, "name":"bjensen", "realm":"/alpha", "exp":1676364398, "tokenType":"JWTToken", "iat":1676360798, "family_name":"Jensen" }Verify the response contains the custom claim added by the script (
myCustomAttrin this example).
Add a session property claim to the profile scope
Complete the following steps to implement an example OIDC claims script that adds a session property claim to the profile scope:
This example adds SSO session details to the ID token and uses the /oauth2/idtokeninfo endpoint to inspect the session property claim values.
|
These steps add the Find a list of the default session properties in Session properties. |
Create the script
This task describes how to modify the default script to map a session property claim.
This example uses a legacy script. Find a next-generation example here.
-
In the AM admin UI, go to Realms > realm name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Groovy
-
JavaScript
-
Add a new claim to the script. For example, insert
AuthLevelafter thenameclaim in theclaimAttributessection as follows:claimAttributes = [ "email": userProfileClaimResolver.curry("mail"), ... "name": userProfileClaimResolver.curry("cn"), "AuthLevel": { claim, identity -> [ (claim.getName()): session.getProperty("AuthLevel") ] } ] -
Add the new claim to the
profilescope in the claims map:scopeClaimsMap = [ "email": [ "email" ], ... "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name", "AuthLevel" ]
-
Add the new
AuthLevelclaim to theprofilescope in theutils.setScopeClaimsMapsection:utils.setScopeClaimsMap({ profile: [ 'name', 'family_name', 'given_name', 'zoneinfo', 'locale', 'AuthLevel' ], email: ['email'], -
Add the new claim to the script. For example, insert
AuthLevelafter thephone_numberclaim in theutils.setClaimResolverssection as follows:utils.setClaimResolvers({ ... phone_number: utils.getUserProfileClaimResolver('telephonenumber'), AuthLevel: function () { return session.getProperty('AuthLevel'); } });
-
-
Save your changes.
The default OIDC claims script is now amended to retrieve a session property claim for the profile scope.
Allowlist the session property
Provide access to the session property to allow it to be output in the ID token.
-
In the AM admin UI, go to Realms > realm name > Services > Session Property Whitelist Service.
-
Add
AuthLevelto the Allowlisted Session Property Names field. -
Save your changes.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
-
Switch to the Advanced OpenID Connect tab to always return scope-derived claims in the ID token.
-
Select Always Return Claims in ID Tokens.
This option is disabled by default because of the security concerns of returning claims that may contain sensitive user information. Learn more in Request claims in ID tokens. -
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofile
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
Save your changes.
AM is now prepared for you to try this sample user info claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMT -
Copy the value of the id_token appended to the redirection URI in the response. You’ll need this value in the next step.
-
Call the /oauth2/idtokeninfo endpoint to inspect the session property claim values, including the ID token obtained from the previous request.
For example:
$ curl \ --request POST \ --user myClient:mySecret \ --data 'id_token=eyJ0eXA…7QdQpg' \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/idtokeninfo" { "at_hash":"PZg5xZsIlFtRSfg8MAWhWg", "sub":"(usr!bjensen)", "auditTrackingId":"2e5c7611-4a61-4001-8739-f714d43e9da2-881454", "subname":"bjensen", "iss":"https://am.example.com:8443/am/oauth2", "tokenName":"id_token", "given_name":"Babs", "nonce":"abc123", "sid":"+buKyDp+Fbc0/Rkd0OqsfdKy7ZY0nWvcsEetikX+eTc=", "AuthLevel":"0", "aud":"myClient", "acr":"0", "org.forgerock.openidconnect.ops":"gkQOcZ1F3ZFdYPd6TiGIgr6scH0", "s_hash":"bKE9UspwyIPg8LsQHkJaiQ", "azp":"myClient", "auth_time":1676360741, "name":"bjensen", "realm":"/alpha", "exp":1676364398, "tokenType":"JWTToken", "iat":1676360798, "family_name":"Jensen" }Verify the response contains the session property claim added by the script (
AuthLevelin this example).
Add a groups claim to the profile scope
Complete the following steps to implement an example OIDC claims script that adds a groups claim to the profile scope:
This example adds group membership details to the ID token and uses the /oauth2/idtokeninfo endpoint to inspect the groups claim values.
Create the script
This task describes how to modify the default script to map a groups claim.
This example uses a legacy script. Find a next-generation example here.
-
In the AM admin UI, go to Realms > realm name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Groovy
-
JavaScript
-
Import the
com.sun.identity.idm.IdTypeclass into the script:import com.iplanet.sso.SSOException … import org.forgerock.openidconnect.Claim import com.sun.identity.idm.IdType -
Add a new claim to the script. For example, insert
groupsafter thenameclaim in theclaimAttributessection as follows:claimAttributes = [ "email": userProfileClaimResolver.curry("mail"), ... "name": userProfileClaimResolver.curry("cn"), "groups": { claim, identity -> [ "groups" : identity.getMemberships(IdType.GROUP).collect { group -> group.name }]} ]You can reformat the claims value returned. For example, replace { group → group.name }in the previous code sample with{ group → 'ROLE_' + group.name }to return the group name with aROLE_prefix. -
Add the new claim to the
profilescope in the claims map:scopeClaimsMap = [ "email": [ "email" ], ... "profile": [ "given_name", "zoneinfo", "family_name", "locale", "name", "groups" ]
-
Add the new
groupsclaim to theprofilescope in theutils.setScopeClaimsMapsection:utils.setScopeClaimsMap({ profile: [ 'name', 'family_name', 'given_name', 'zoneinfo', 'locale', 'groups' ], email: ['email'], -
Add the new claim to the script. For example, insert
groupsafter thephone_numberclaim in theutils.setClaimResolverssection as follows:utils.setClaimResolvers({ ... phone_number: utils.getUserProfileClaimResolver('telephonenumber'), groups: function() { var fr = JavaImporter( com.sun.identity.idm.IdType ); var groups = []; identity.getMemberships(fr.IdType.GROUP).toArray().forEach(function(group) { groups.push(group.getAttribute('cn').toArray()[0]); }); return groups; } });
-
-
Save your changes.
The default OIDC claims script is now amended to retrieve a groups claim for the profile scope.
Allowlist the Java class
Allow the script to access the Java class you imported.
-
In the AM admin UI, go to Configure > Global Services > Scripting > Secondary Configurations > OIDC_CLAIMS > Secondary Configurations > engineConfiguration.
-
Add
com.sun.identity.idm.IdTypeto the Java class whitelist field. -
Save your changes.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
-
Switch to the Advanced OpenID Connect tab to always return scope-derived claims in the ID token.
-
Select Always Return Claims in ID Tokens.
This option is disabled by default because of the security concerns of returning claims that may contain sensitive user information. Learn more in Request claims in ID tokens. -
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofile
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
Save your changes.
AM is now prepared for you to try this sample user info claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMT -
Copy the value of the id_token appended to the redirection URI in the response. You’ll need this value in the next step.
-
Call the /oauth2/idtokeninfo endpoint to inspect the groups claim values, including the ID token obtained from the previous request.
For example:
$ curl \ --request POST \ --user myClient:mySecret \ --data 'id_token=eyJ0eXA…7QdQpg' \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/idtokeninfo" { "at_hash":"PZg5xZsIlFtRSfg8MAWhWg", "sub":"(usr!bjensen)", "auditTrackingId":"2e5c7611-4a61-4001-8739-f714d43e9da2-881454", "subname":"bjensen", "iss":"https://am.example.com:8443/am/oauth2", "tokenName":"id_token", "groups": [ "supervisors", "employees" ], "given_name":"Babs", "nonce":"abc123", "sid":"+buKyDp+Fbc0/Rkd0OqsfdKy7ZY0nWvcsEetikX+eTc=", "aud":"myClient", "acr":"0", "org.forgerock.openidconnect.ops":"gkQOcZ1F3ZFdYPd6TiGIgr6scH0", "s_hash":"bKE9UspwyIPg8LsQHkJaiQ", "azp":"myClient", "auth_time":1676360741, "name":"bjensen", "realm":"/alpha", "exp":1676364398, "tokenType":"JWTToken", "iat":1676360798, "family_name":"Jensen" }Verify the response contains the groups claim added by the script (
groupsin this example).
Override the audience and issuer claims
Complete the following steps to implement an example OIDC claims script that overrides the aud (audience) and iss (issuer) claims:
This example overrides the aud and iss claims in the ID token and uses the /oauth2/idtokeninfo endpoint to inspect the overridden claims.
|
These steps override the For information about the core OIDC claims, refer to the ID Token data structure. |
Create the script
This task describes how to modify the default script to override the aud and iss claims.
This example uses a legacy script. Find a next-generation example here.
-
In the AM admin UI, go to Realms > realm name > Scripts, and click OIDC Claims Script.
-
In the Script field:
-
Groovy
-
JavaScript
-
Add the claim override details after the existing
computedClaimsline. You can specify overrides as a string or an array. For example, add anissoverride as a string:computedClaims = claimsToResolve.collectEntries() { claim -> result = computeClaim(claim) } computedClaims.put("iss", "https://example.com") -
Then add an
audoverride as an array:def audClaim = ["myClient","testClient"]; computedClaims.put("aud", audClaim)
-
Add the claim override details before the
return computedClaims;line. You can specify overrides as a string or an array. For example, add anissoverride as a string:computedClaims.put("iss", "https://example.com") return computedClaims; -
Then add an
audoverride as an array:var audClaim = ["myClient","testClient"]; computedClaims.put("aud", audClaim)
The
audoverride values you specify must correspond to registered clients; otherwise you’ll see an error when you inspect the claim values.Replace
testClientin the script above with the ID of another registered OAuth2 client, or create a temporary OAuth2 client calledtestClientfor testing purposes. -
-
Save your changes.
The default OIDC claims script is now amended to override claims.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
-
Switch to the Advanced OpenID Connect tab to always return scope-derived claims in the ID token.
-
Select Always Return Claims in ID Tokens.
This option is disabled by default because of the security concerns of returning claims that may contain sensitive user information. Learn more in Request claims in ID tokens. -
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofile
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
On the OAuth2 Provider Overrides tab, select Enable OAuth2 Provider Overrides.
-
Enter
audissin the Overrideable Id_Token Claims field.You can specify the claims to override in the OAuth2 Provider instead. The Overrideable Id_Token Claims field is on the OpenID Connect tab in the provider. -
Save your changes.
AM is now prepared for you to try this sample OIDC claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMT -
Copy the value of the id_token appended to the redirection URI in the response. You’ll need this value in the next step.
-
Call the /oauth2/idtokeninfo endpoint to inspect the overridden claims, including the ID token obtained from the previous request.
For example:
$ curl \ --request POST \ --user myClient:mySecret \ --data 'id_token=eyJ0eXA…7QdQpg' \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/idtokeninfo" { "at_hash":"PZg5xZsIlFtRSfg8MAWhWg", "sub":"(usr!bjensen)", "auditTrackingId":"2e5c7611-4a61-4001-8739-f714d43e9da2-881454", "subname":"bjensen", "iss":"https://example.com", "tokenName":"id_token", "given_name":"Babs", "nonce":"abc123", "sid":"+buKyDp+Fbc0/Rkd0OqsfdKy7ZY0nWvcsEetikX+eTc=", "aud": [ "myClient", "testClient" ], "acr":"0", "org.forgerock.openidconnect.ops":"gkQOcZ1F3ZFdYPd6TiGIgr6scH0", "s_hash":"bKE9UspwyIPg8LsQHkJaiQ", "azp":"myClient", "auth_time":1676360741, "name":"bjensen", "realm":"/alpha", "exp":1676364398, "tokenType":"JWTToken", "iat":1676360798, "family_name":"Jensen" }Verify the response contains the overridden
issandaudvalues.
Example using a next-generation script
The following example demonstrates how to add a custom claim to the profile scope using a next-generation script.
The example uses the /oauth2/userinfo endpoint to inspect the custom claim values.
Create the OIDC claims script
This task describes how to create a new next-generation script to map custom claims.
-
In the AM admin UI, go to Realms > realm name > Scripts > + New Script, enter the following values:
-
Name:
Demo OIDC claims -
Script Type:
OIDC Claims -
Evaluator Version:
Next Generation
-
-
In the Script field, paste the following JavaScript:
(function () { var computedClaims = {}; var compositeScopes = {}; function getAttribute(attrName) { var values = identity.getAttributeValues(attrName); return (values && values.size() > 0 ? values[0] : null); } // Use the 'identity' binding to fetch user profile data if (identity) { var cn = getAttribute('cn'); var sn = getAttribute('sn'); var gn = getAttribute('givenName'); // Map standard OIDC claims if (cn) computedClaims['name'] = cn; if (sn) computedClaims['family_name'] = sn; if (gn) computedClaims['given_name'] = gn; // Add custom claim if (gn && sn) { computedClaims['custom_string'] = gn + "_" + sn; } } // Map claims to requested scopes for each(var scope in scopes) { // Map claims to the 'profile' scope, including our custom ones if (scope === 'profile') { compositeScopes['profile'] = [ 'name', 'family_name', 'given_name', 'custom_string' ]; } else if (scope === 'email') { compositeScopes['email'] = ['email']; } } // The script must return an object with exactly two properties: // 'values' and 'compositeScopes' return { values: computedClaims, compositeScopes: compositeScopes }; }()); -
Save your changes.
The new OIDC claims script is now ready to retrieve a custom claim for the profile scope.
Configure the provider
Perform this task to set up an OAuth 2.0 provider to use your custom script.
-
Configure the provider and make sure the following properties are set:
-
OIDC Claims Plugin Type to
SCRIPTED. -
OIDC Claims Script to the name of your custom script.
-
-
Save your changes.
-
Switch to the Advanced OpenID Connect tab to always return scope-derived claims in the ID token.
-
Select Always Return Claims in ID Tokens.
This option is disabled by default because of the security concerns of returning claims that may contain sensitive user information. Learn more in Request claims in ID tokens. -
Save your changes.
Create a client application
Create a public OAuth 2.0 client to use in the authorization request.
-
In the AM admin UI, go to Realms > realm name > Applications > OAuth 2.0 > Clients, and click Add Client.
-
Enter the following values:
-
Client ID:
myClient -
Client secret:
mySecret -
Redirection URIs:
https://www.example.com:443/callback -
Scope(s):
openidprofile
-
-
Click Create.
-
On the Core tab, set Client type to
Public, and click Save. -
On the Advanced tab, set the following values:
-
Response Types:
token id_token -
Grant Types:
Implicit -
Token Endpoint Authentication Method:
none
-
-
Save your changes.
AM is now prepared for you to try this sample user info claims script.
Try the script
To try your custom script, use the Implicit grant flow as demonstrated in the following steps.
-
Log in to AM as a test user, for example:
$ curl \ --request POST \ --header "Content-Type: application/json" \ --header "X-OpenAM-Username: bjensen" \ --header "X-OpenAM-Password: Ch4ng31t" \ --header "Accept-API-Version: resource=2.0, protocol=1.0" \ 'https://am.example.com:8443/am/json/realms/root/realms/alpha/authenticate' { "tokenId":"AQIC5wM…TU3OQ*", "successUrl":"/am/console", "realm":"/alpha" }Copy the SSO token value returned as
tokenIdin the output. You’ll need this value in the next step. -
Invoke the authorization server’s /oauth2/authorize endpoint specifying the SSO token value in a cookie, and the following parameters as a minimum:
-
client_id=
myClient -
response_type=
token id_token -
scope=
openid profile -
nonce=your nonce value
-
redirect_uri=
https://www.example.com:443/callback -
decision=
allow -
csrf=SSO-token
For example:
$ curl --dump-header - \ --cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \ --request POST \ --data "client_id=myClient" \ --data "response_type=token id_token" \ --data "scope=openid profile" \ --data "state=123abc" \ --data "nonce=abc123" \ --data "decision=allow" \ --data "csrf=AQIC5wM…TU3OQ*" \ --data "redirect_uri=https://www.example.com:443/callback" \ "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/authorize" HTTP/1.1 302 X-Frame-Options: SAMEORIGIN X-Content-Type-Options: nosniff Cache-Control: no-store Location: https://www.example.com:443/callback#access_token=az91IvnIQ-uP3Eqw5QqaXXY_DCo&id_token=eyJ0eXA…7QdQpg&state=123abc&token_type=Bearer&expires_in=3599 Pragma: no-cache Set-Cookie: OAUTH_REQUEST_ATTRIBUTES=DELETED; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly Content-Length: 0 Date: Mon, 01 Jul 2024 14:10:09 GMT -
-
Copy the value of the
access_tokenappended to the redirection URI in the response. You’ll need this value in the next step. -
Call the /oauth2/userinfo endpoint to inspect the custom claim values, including the access token obtained from the previous request.
For example:
$ curl \ --request GET \ --header "Authorization: Bearer <access-token>" \ 'https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/userinfo' { "name":"bjensen", "given_name":"Babs", "family_name":"Jensen", "custom_string": "Babs_Jensen" }
Verify the response contains the custom claim, custom_string, added by the script.