Auth0 doesn’t just authenticate users; it’s a powerful metadata store for both your users and your applications.
Let’s see it in action. Imagine a user logs in to your app. Auth0 handles the authentication, and then it passes back not just a token, but a rich payload of information. This payload can include their name, email, and crucially, custom data you’ve attached.
{
"sub": "auth0|1234567890abcdef",
"name": "Jane Doe",
"email": "jane.doe@example.com",
"https://myapp.com/roles": ["admin", "editor"],
"https://myapp.com/plan": "premium"
}
This isn’t magic; it’s configured through Auth0’s "User Metadata" and "App Metadata" features.
User Metadata is for information specific to a user. Think of roles, subscription plans, user preferences, or any other attribute that differentiates one user from another. You can set this directly on the user’s profile in the Auth0 dashboard or programmatically via the Auth0 Management API.
App Metadata is for information about the application itself, or attributes that apply to all users of a specific application. For instance, if you have different "tiers" of your application (e.g., "Free," "Pro," "Enterprise"), you could store that tier information in App Metadata. This could then be used to conditionally show features within the application.
The real power comes from how this metadata is integrated into the authentication flow. Auth0 Rules and Hooks (or the newer Actions) are the key. These are JavaScript snippets that run after a user authenticates but before a token is issued. You can use them to:
- Fetch external data: If user metadata isn’t directly in Auth0 (e.g., it lives in your CRM), a Rule can fetch it.
- Augment existing metadata: Add dynamic information based on other user attributes.
- Enforce policies: Deny access if certain metadata conditions aren’t met.
- Map to token claims: Crucially, you can map this metadata directly into the ID or Access Tokens as custom claims. This is what allows your frontend or backend to easily access and act upon this information without needing a separate API call to Auth0.
Let’s say you want to add a tenant_id to every token for a user. You’d create an Action (or Rule) that looks something like this:
// Example using Auth0 Actions (Node.js)
exports.onExecutePostLogin = async (event, api) => {
// Assume tenant_id is stored in user metadata
const tenantId = event.user.user_metadata.tenant_id;
if (tenantId) {
api.idToken.setCustomClaim("https://myapp.com/tenant", tenantId);
api.accessToken.setCustomClaim("https://myapp.com/tenant", tenantId);
}
};
This Action would run on every successful login. If the user has tenant_id in their user_metadata, it gets added to both the ID and Access tokens under the https://myapp.com/tenant claim. Your application can then read this claim from the token and route the user to their specific tenant’s data.
The distinction between User Metadata and App Metadata is essential. User Metadata is user-specific, while App Metadata is application-specific. However, both can be used to populate custom claims in tokens. The key is the namespace you use for the claim – https://myapp.com/ is a common convention to avoid conflicts with standard claims.
When you’re designing your system, consider where data belongs. Is it a property of the user (e.g., their chosen theme)? Or is it a property of the application that affects all users within that application context (e.g., the specific feature set enabled for that application instance)?
The most surprising true thing about Auth0 metadata is that it’s not just a simple key-value store; it’s deeply integrated into the token issuance pipeline. This means you can bypass separate API calls to fetch user context after authentication, leading to simpler, more performant applications.
If you’re using Auth0, you’ll eventually need to manage the lifecycle of this metadata, especially when users or applications change. This often involves integrating with your own backend systems via the Auth0 Management API to keep your Auth0 metadata synchronized with your primary data sources.