Hi @max17
Welcome to the Auth0 Community!
I understand you are asking why Organization information set as a custom claim in a post-login action does not appear in your ID token, and why the claim disappears after a “Successful Silent Login” event even though it was successfully set during the initial login.
The root cause is that custom claims set only in the post-login action are not automatically re-applied during silent authentication (token refresh). The “Successful Silent Login” event you see is Auth0 refreshing your tokens using the refresh token flow, which does not re-execute your post-login action with the same context. Custom claims must either be persisted in user metadata or app_metadata to survive token refresh, or your action must be designed to retrieve organization data from a persistent source during every token issuance.
Root Cause:
When a user logs in silently (via getTokenSilently() or checkSession() in your React application), Auth0 uses the refresh token to mint new tokens without re-running the full post-login flow. Your post-login action executes only during the initial interactive login. Any custom claim you set there is included in the first token, but when the token expires and is silently refreshed, the action does not run again with the same event.organization context, so the claim is lost.
Solution:
To persist organization information across token refreshes, store the organization ID in the user’s app_metadata during the post-login action, then retrieve it on every token issuance (including silent refreshes). Follow these steps:
- Update your post-login action to store the organization ID in app_metadata:
exports.onExecutePostLogin = async (event, api) => {
if (event.organization && event.organization.id) {
// Store organization info in app_metadata for persistence
api.user.setAppMetadata('organization_id', event.organization.id);
api.user.setAppMetadata('organization_name', event.organization.name);
}
// Add to token using the stored metadata (works on initial login)
const orgId = event.user.app_metadata?.organization_id || event.organization?.id;
const orgName = event.user.app_metadata?.organization_name || event.organization?.name;
if (orgId) {
api.idToken.setCustomClaim(
'https://cats.dev-thepioneers.com/organizations',
{
pioneers_org_id: orgId,
pioneers_org_name: orgName,
}
);
}
};
-
Verify the claim is namespaced correctly. Your claim URL
https://cats.dev-thepioneers.com/organizationsis correctly namespaced (Auth0 requires custom claims to use a URL namespace to avoid collisions). This is not the issue. -
Decode and inspect both tokens to confirm the claim appears in the initial ID token. Use a JWT decoder (such as jwt.io) to verify the claim is present immediately after login.
-
Check your React application’s token caching. If you are using the Auth0 React SDK (
useAuth0()hook), verify thatgetIdTokenClaims()is being called after the initial login completes, not from a cached value. The SDK may cache the decoded token; if the cache is not invalidated after a silent refresh, you may see stale claims. -
Test silent authentication in isolation. Call
getTokenSilently()directly in your React app and decode the returned token to confirm whether the claim is actually missing from the new token, or whether it is present in the token but not being read by your application.
Sources:
- Customs claims are lost after refresh token
- How can I get organizationId in sisense if I use auth0 with SAML 2
Hope the above information have helped you overcome the issue, but feel free to reach out to us for any other issue or request!
Have a great one,
Gerald