Custom Claim
Overview
LoginRadius supports enriching JWT access tokens and ID tokens with custom claims. These claims allow you to embed additional user, or contextual metadata directly into tokens during OAuth 2.0, OpenID Connect (OIDC), JWT login flows.
By injecting custom claims at authentication time, downstream applications—such as APIs, gateways, or microservices—can make authorization decisions without extra API calls, improving performance, scalability, and flexibility.
LoginRadius provides two methods for adding custom claims:
- JWT Template Mapping — Use the JSON template editor in the admin console (Applications > Add/Edit application under Tokens tab or SSO Integrations > JWT Integration ) to map static values or dynamic user profile fields directly into token claims.
- Script-Based Injection — Use Identity Orchestration (IO) Scripts to write JavaScript logic that dynamically computes and injects claims, including external API calls and conditional rules.
Use Cases
-
Role-Based Access Control (RBAC): Embed user roles or group memberships directly into the token to drive fine-grained access control in downstream services.
-
Session Context: Include session-specific data (e.g., login time, device ID) to enforce policies like session expiration or device-based access.
-
Custom Authorization Logic: Derive and inject claims based on custom business rules using scripts, for example, marking VIP users or enforcing region-specific restrictions.
-
Reduced Latency for API Gateways: Allow API gateways and services to authorize requests without making extra calls to identity or profile APIs.
Key Features
-
Seamless Integration with OAuth/OIDC Flows Both methods are applied automatically during authentication — scripts via the orchestration workflow, templates via the application's Tokens configuration.
-
Dynamic Claims Logic (Script-Based) Supports complex logic using JavaScript (Node.js), including conditional rules, external API calls, and custom computations.
-
JSON Template Editor Define custom claims via a JSON template in the admin console without writing scripts. Supports dynamic user profile values, static values, dot notation for nested fields, array indexing, fallback defaults, and string concatenation.
-
Claims Injected at Token Generation Time Custom claims are evaluated and included at the final stage of token generation, ensuring up-to-date and context-aware data. Custome claims can not modify the registered claims like: iss ,nbf, jti, exp, aud, amr etc, it can only add additional claims
Configurations
Method 1: JWT Template Mapping
JWT Template Mapping lets you define custom claims using a JSON template directly in the admin console — no scripting required. You map claim keys to static values or dynamic user profile fields using {{ }} placeholders.
Follow the steps below:
-
Open Application Settings:
- Navigate to Applications.
- Select an existing OIDC/OAuth application or create a new one.
- Open the application and go to the Tokens tab.
-
Edit the JWT Template:
- In the JWT Templates Mapping section, a text area displays a sample JSON template.
- Edit the JSON to define the claims you want to include. Use
{{ }}placeholders to insert dynamic values from the user profile, or enter static string/number values directly.
Below is a sample template for reference:
{"email": "{{ Email.0.Value }}","full_name": "{{ FirstName }} {{ LastName }}","location": "{{ City }}, {{ State }}","country_code": "{{ Country.Code }}","country_name": "{{ Country.Name }}","account_type": "enterprise"} -
Validate and Save:
- The admin console performs JSON syntax validation before saving. Malformed JSON will surface an inline error.
- Once the template is valid, save the application. Claims defined in the template will be injected into issued access tokens and ID tokens automatically.
For template placeholder syntax, see Template Syntax below.
Template Syntax
JWT templates use {{ }} placeholders to insert dynamic values from the authenticated user's profile. You can also use static values for any claim — simply provide a string or number without a placeholder.
Simple Variable
Insert a top-level field from the user profile:
{
"LastName": "{{ LastName }}"
}
Nested Properties
Access nested fields using dot notation:
{
"language": "{{ user.metadata.language }}"
}
Array Access
Access array elements using a 0-based index:
{
"email": "{{ Email.0.Value }}"
}
Fallback Values
Use || to provide a default when a field is missing or null:
{
"name": "{{ user.LastName || 'Guest' }}"
}
String Concatenation
Combine multiple placeholders in a single string value:
{
"full_name": "{{ FirstName }} {{ LastName }}"
}
Object Insertion
Insert an entire object or array from the profile:
{
"metadata": "{{ user.metadata }}"
}
Use dot notation and array indexing as shown in the Template Syntax section to reference any of these fields in your template.
Method 2: Script-Based Injection (IO Scripts)
Orchestration supports OIDC and OAuth 2.0, and with the IO scripts, you can add custom claims to JWT tokens dynamically. Follow the steps below:
-
Create Application:
- Navigate to Applications.
- Create a new OIDC/OAuth application using the Add Apps button or select an existing application.
- Store the client ID, client secret, and application name.
-
Create a script to set custom claims:
- Go to Orchestration > Scripts
- Click on + New Script and set the script name.
- Create a script as per your requirements and set custom claims in access_token and/or idToken using
hook.accessToken.setCustomClaim()andhook.idToken.setCustomClaim()and save.
Below is a script for your reference
const axios = require('axios');exports.execute = async (lrObject, hook) => {try {const response = await axios.get('https://blue-truth-6f59.mayankagrwal.workers.dev/');if (response){var role = response.data?.role;var permissions = response.data?.permissions;if (role) {hook.accessToken.setCustomClaim('role', role);hook.idToken.setCustomClaim('role', role);}if (permissions && permissions.length) {hook.accessToken.setCustomClaim('permissions', permissions.join(","));hook.idToken.setCustomClaim('permissions', permissions.join(","));}}} catch (error) {// Fail the flow with a custom error messagehook.setError('500', 'API Error', error.message);}};For more information on scripts, refer to this
-
Create IO Workflow:
-
Navigate to Orchestration > Workflow
-
Create a new workflow by clicking on New Workflow. Or select an existing one.
-
From the left panel, drag and drop the Scripts node under Helper Nodes, then place it after the Auth node.
-
Click the Script node, then select the script name set in step 1.
-
Once done, save and update the workflow
-
How it works
Both methods inject claims at the same point — the final stage of token generation. The difference is in how the claims are defined:
- Script-Based: The IO Script runs inside the orchestration workflow after authentication, computes claims dynamically, and calls
hook.accessToken.setCustomClaim()/hook.idToken.setCustomClaim(). - JWT Template Mapping: The template defined in the application's Tokens tab is evaluated at token issuance — placeholders are resolved against the authenticated user's profile and the resulting claims are added to the token payload.
The authorization flow is the same for both methods:
-
Initiate login
-
Use the
/authorizeendpoint to start OIDC authorization. -
Provide workflow (required for script-based), client ID, and OIDC app name as shown below.
https://<siteUrl>/service/oidc/<AppName>/authorize?client_id=<clientID>&redirect_uri=http%3A%2F%2Flocalhost%3A3000&response_type=code&scope=openid%20email%20profile&state=<random>&workflow=<workflowName>&debugmode=false -
Once the user logs in, custom claims are injected into the token payload — either via the script or the template, depending on your configuration.
-
Exchange code for tokens
Use the
/tokenendpoint to exchange the code received from Step 1. For examplecurl --location 'https://<site url>/api/oidc/<OIDC App name>/token' \--header 'Content-Type: application/json' \--data '{"client_id":"<client ID>","client_secret":"<client secret>","redirect_uri":"http://localhost:3000","response_type":"token","grant_type":"authorization_code","code":"<code>"}'
The resulting access_token and id_token will include your custom claims. For more information, refer to this.
Best Practices
-
Handle Errors Gracefully (Script-Based): Use
hook.setErrorto handle validation or execution errors in IO Scripts. -
Always Validate Input (Script-Based): Ensure that fields like
lrObject.Identity.Emailexist before accessing them to avoid runtime errors. -
Use Fallback Values for Optional Fields (Template Mapping): Wrap fields that may be absent using the
|| 'default'syntax to prevent null or missing claims (e.g.,{{ user.metadata.region || 'global' }}). -
Validate JSON Before Saving (Template Mapping): Use the built-in admin console validator — malformed JSON will be rejected before it can affect token issuance.
-
Don't expose client secret: Always use the client secret in your backend server to avoid data breaches and security issues.