Add claims to JWT through Actions on Auth0
β’ 5 minute read
auth0, jwt
Table of contents
Recently, I came up with a solution to handle single sign-on (SSO) internally for all enterprise applications inside the company. This scenario is typically known as B2E or workforce. Look at the Gartner report about Critical Capabilities for Access Management for more details. So, for example, if a company uses Azure AD for its employees, the companies's internal application can use it to grant access (authentication), and allow a user to execute something or not (permission).
What will we do?
This post is the first of two where I will demonstrate how we can achieve SSO with Django applications for the B2E scenario, focused on The Django admin site, through Auth0.
Managing permissions through claims
The idea is quite simple: after the user's login, we'll include all groups he belongs to inside a custom claim. Of course, this strategy is not production-ready, but let's keep things simple for the article's sake. Let's see an image that illustrates the whole flow:
The dashed orange circle denotes the step where we'll add a custom claim.
Adding Action during post-login trigger
To add an Action, we first should choose one of the flows available:
Let's pick login flow following the sequence diagram we saw earlier. Next, click on the plus symbol and choose Build Custom.
Put the name Enrich JWT with Groups from AD and click on Create.
You should see the following image:
Reading the methods that we can implement, we should pick the onExecutePostLogin
. The onContinuePostLogin
allows us to require further steps after authentication before letting the user continue to the application where the flow started. The Redirect with Actions article can give you further details.
Now, let's see the code:
exports.onExecutePostLogin = async (event, api) => {
// Collecting secrets
const tenant = event.secrets.TENANT
const audience = event.secrets.AUDIENCE
const clientId = event.secrets.APP_CLIENT_ID
const clientSecret = event.secrets.APP_CLIENT_SECRET
// Creating management API
const ManagementClient = require("auth0").ManagementClient
const managementClient = new ManagementClient({
domain: `${tenant}.us.auth0.com`,
scope: "read:users",
clientId,
clientSecret,
audience,
})
// Main routine
const userId = event.user.user_id
const user = await managementClient.getUser({ id: userId })
const shouldEnrichJWTWithGroups = user.hasOwnProperty("groups")
if (shouldEnrichJWTWithGroups) {
const claimKey = "https://www.willianantunes.com/ad/groups"
const claimValue = user.groups
api.idToken.setCustomClaim(claimKey, claimValue)
}
}
An essential thing to mention here is the part where we use the Management API. It has rate limits, so we're leaving it this way just for the article's sake. With that said, let's explain the script:
- First, we collect "must have" secrets.
- We use the secrets from the previous step to instantiate a class to deal with the Management API.
- We retrieve all user attributes given the user ID.
- If the user has the root attribute
groups
, we add it as a custom claim in the ID token.
You might be thinking: Why do we use the Management API if the Action delivers user attributes also including "application metadata"? Sadly, some attributes are not available, and groups
is one of them. I found this explanation on Auth0 Community, but still, it's not available.
Depending on how you configure your enterprise connection with the directory service, it may include the root attribute groups
. For example, look at how I configured mine for testing purposes:
Action limitations
Consulting Auth0 Management API all the time is cumbersome. Sadly we can't circumvent that because of current Actions limitations. I recommend you read this community post where there is an official statement by the Auth0 community moderator.
Why not Rules?
The problem with Auth0 Rules is its expected deprecation sometime in the second half of 2022. Although it has many OOTB solutions, Actions will rule over it soon. You can consult Actions marketplace and check out some samples that can help you migrate or create new things.
Conclusion and next steps
Our next article will use the post-login trigger we wrote here with a full-blown solution, including Django with Mozilla Django OIDC and Auth0 Deploy CLI. Stay tuned π!
See everything we did here on GitHub.
Posted listening to A nova bossa Γ© violΓ£o, Paulinho Nogueira πΆ.