LinkedIn Social Connection - "locale" Claim is an Object Instead of a String

Overview

While the Open ID Connect (OIDC) specs state the “locale” claim as a string:

https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims:~:text=America/Los_Angeles.-,locale,string,-End%2DUser%27s%20locale

LinkedIn returns an object as a value for that attribute, and Auth0 also takes it as an object in the normalized user profile.

This document proposes a solution to pass a flattened “locale” attribute in the token using Actions.

Applies To

  • LinkedIn Social Connection
  • “locale” claim

Cause

LinkedIn is returning the ID Token with the “locale” claim in an object format instead of a string.

This is the ID Token from LinkedIn:

{

"sub": "linkedin|Gxxxxx",

"given_name": "<First Name>",

"family_name": "<Last Name>",

"nickname": "<Nickname>",

"name": "<Full Name>",

...

"locale": {

"country": "ES",

"language": "es"

},

"updated_at": "2025-07-02T15:31:58.178Z",

"iss": "[https://<domain>.auth0.com/](https://dse-laura.us.auth0.com/)",

"aud": "<aud>",

"iat": 1751470394,

"exp": 1751506394,

"sid": "<sid>",

...

}

Auth0 is taking that claim and storing it in the user profile as an object:

{
"created_at": "2025-07-01T23:40:19.372Z",
"family_name": "<Last Name>",
"given_name": "<First Name>",
"identities": [
{
"provider": "linkedin",
"user_id": "Gxxxxxxx",
"connection": "linkedin",
"isSocial": true
}
],
"locale": {
"country": "ES",
"language": "es"
},
"name": "<Full Name>",
"nickname": "<Nickname>",
...
"sub": "xxxz",
"updated_at": "2025-07-02T15:55:57.034Z",
"user_id": "linkedin|Gxxxxxxx",
"last_ip": "<IP Address>",
"last_login": "2025-07-02T15:55:57.033Z",
"logins_count": 9,
"blocked_for": [],
"guardian_authenticators": [],
"passkeys": []
}

Solution

Create a Post Login Action to flatten the locale scope and then add it to a custom claim on the IDToken:

/**
* Flatten the locale scope if it's not a string
*/
exports.onExecutePostLogin = async (event, api) => {
const { locale } = event.user;
if (typeof locale === "object") {
// linkedin sets the locale as an object like this:
// "locale": {
// "country": "US",
// "language": "en"
//},

// flatten the locale:
api.idToken.setCustomClaim(
"locale",
${locale.language}-${locale.country}``
);
}
};

See Create custom claims for more details on setting custom claims with Actions.