Which auth providers support roles and permissions out of the box?
Short answer
Auth0, Clerk, WorkOS, Kinde and Logto have both roles and permissions built in, and Keycloak, Zitadel and FusionAuth focus on roles. Amazon Cognito only has groups, while Firebase Auth and Supabase leave roles to custom claims you set yourself. The providers differ most in whether roles reach the token by default and whether they are per organization. loginos puts roles and permissions in every token.
You are choosing an identity provider, or checking the one you have, and you don’t want to build authorization from scratch. Almost every provider mentions RBAC (role-based access control: people get roles, and roles grant permissions). The real differences are where you define roles, whether they reach the token without extra code, and whether one person can hold a different role in each customer organization.
Each entry below was checked against the vendor’s documentation in October 2026. Products change often, so confirm the details in their docs before you commit.
Which auth providers have roles and permissions built in?
The table compares eleven providers and loginos. “Per organization” means a person can hold a different role in each organization or tenant inside one user pool.
| Provider | Roles in a UI | Permissions | In the token by default | Per organization | Change by API |
|---|---|---|---|---|---|
| Auth0 | Yes | Yes, per API | With an API setting or an Action | With Organizations | Yes |
| Clerk | Yes | Yes | Yes | Only per organization | Yes |
| WorkOS | Yes | Yes | Yes | Only per organization | Yes |
| Kinde | Yes | Yes | Permissions yes, roles with a setting | Only per organization | Yes |
| Logto | Yes | Yes | With a scope | Global and per organization | Yes |
| Keycloak | Yes | Roles, plus Authorization Services | In the access token | Through organization groups | Yes |
| Zitadel | Yes | Roles only | With a setting or scope | Per organization | Yes |
| FusionAuth | Yes | Roles only | In the access token | Per application | Yes |
| Amazon Cognito | Groups | Groups only | Yes, as cognito:groups | No | Yes |
| Firebase Auth | No | No | With custom claims | No | Yes, custom claims |
| Supabase Auth | No | No | With a hook | No | Yes, app_metadata |
| loginos | Yes | Yes | Yes | No, per platform | Yes |
How do the providers differ?
Auth0
Auth0 defines permissions on APIs, like read:reports on a reports API, and groups them into roles in the dashboard. Turn on Enable RBAC and Add Permissions in the Access Token in an API’s settings, and access tokens for that API carry a permissions array. Roles never appear by default. A post-login Action reads event.authorization.roles and adds them with api.idToken.setCustomClaim or api.accessToken.setCustomClaim.
Auth0 recommends namespaced claim names to avoid collisions. You can’t name the claim roles anyway: roles, permissions and groups are restricted, so use a name like https://example.com/roles. Auth0 Organizations let a member hold different roles in each organization, and roles that exist only inside one organization are in Early Access.
Clerk and WorkOS
Clerk has roles and permissions only inside Organizations. It ships two default roles, org:admin and org:member, and custom permissions follow the pattern org:<feature>:<permission>. A member holds one role per organization. The session token’s o claim carries the role (o.rol) and permission names (o.per) for the active organization, and Clerk’s nine system permissions are left out. For app-wide roles, Clerk documents a workaround: keep the role in publicMetadata and add it to the session token as a custom claim.
WorkOS also ties roles to organization memberships, so there is no global role. Roles and permissions defined in the dashboard are shared by all organizations, and each organization can add custom roles. The AuthKit access token carries org_id, role and permissions for the organization selected at sign-in, and you refresh the session with another organization_id to switch. WorkOS can also assign roles from your customers’ directory or SSO groups.
Kinde and Logto
Kinde defines roles once for your business and assigns them per organization, so one person can be an admin in one organization and a member in another. People with no known organization go into a default one. The access token carries permissions for the organization the person signed in to. A roles claim appears only after you switch on Roles (array) in the application’s token settings.
Logto has both kinds: global roles, whose permissions belong to API resources, and organization roles from one shared organization template. An access token for an API resource lists the granted permissions in its scope claim. The ID token and userinfo include roles and organization_roles when you request the matching scopes. Logto is open source and can be self-hosted.
Keycloak, Zitadel and FusionAuth
Keycloak is an open-source server you run yourself. It has realm roles, client roles scoped to one application, composite roles that contain other roles, and default roles for new users. Its built-in roles client scope puts them in the access token as realm_access.roles and resource_access.<client>.roles, but not in the ID token unless you change the mapper. For permissions on resources, its Authorization Services module adds policies. Each realm is a separate user pool, and since version 26.7, roles can be assigned to organization groups.
Zitadel defines roles per project, and a role is a key with a display name, without a list of permissions. Roles are assigned to a user in an organization, and the claim urn:zitadel:iam:org:project:{projectId}:roles maps each role to the organizations where the person holds it. Roles appear only when configured or requested: turn on Assert Roles on Authentication for the project and the role setting on the app, or request a roles scope.
FusionAuth defines roles per application, with default roles for new registrations. A registration links a user to one application and holds the user’s roles there. The access token has a roles claim for the application the person signed in to, but the ID token stopped carrying roles in version 1.24.0. You change roles by updating the registration with PUT /api/user/registration/{userId}/{applicationId}.
Amazon Cognito, Firebase Auth and Supabase Auth
Amazon Cognito has groups, not roles or permissions. Groups can’t be nested, and each can map to an IAM role. Cognito adds cognito:groups to the ID and access tokens when the user is in at least one group, with up to 100 groups per user. Other claims need a pre token generation Lambda trigger, and changing access tokens needs trigger version 2 or 3, which not every feature plan includes.
Firebase Auth has no roles, only custom claims. Your server sets them with the Admin SDK’s setCustomUserClaims(uid, claims), and the payload may be at most 1,000 bytes. The claims sit at the top level of the ID token, and Security Rules read them as request.auth.token.<claim>.
Supabase Auth has no role or permission builder either. The role claim in its tokens is the Postgres role, like authenticated, not your app’s role. Supabase’s RBAC guide keeps roles and permissions in your own tables and adds a user_role claim with a custom access token hook: a Postgres function or HTTP endpoint that runs before a token is issued. Never authorize on user_metadata, because users can edit it.
How do you choose a provider for roles and permissions?
Work through these five questions before you compare prices or SDKs:
- Global or per-organization roles? If your customers are companies with their own admins, you need a role per person per organization. Clerk, WorkOS, Kinde and Zitadel assign roles per organization, and Auth0 and Logto offer both kinds. With the others, you model it with realms, groups or your own tables, as in multi-tenant login.
- Do permissions arrive in the token? Code that checks
posts:publishkeeps working when you reshape roles. Clerk, WorkOS and Kinde send permissions without setup, and Auth0 after one setting per API. Keycloak, Zitadel, FusionAuth and Cognito send roles or groups, so your code maps them to permissions. The JWT answer explains why permission checks age better. - How big will the token get? Every claim travels with every request. Firebase caps custom claims at 1,000 bytes, and Clerk advises keeping custom session claims under 1.2 KB, because browsers limit cookies to 4 KB. If people can hold hundreds of permissions, send roles and expand them on your server.
- Can your backend change roles? Check that the management API can assign roles, not only read them. Auth0 adds roles with
POST /api/v2/users/{id}/roles, Clerk changes a membership withPATCH /organizations/{organization_id}/memberships/{user_id}, and Firebase replaces all custom claims on every call. Everywhere, a token keeps the old roles until a new one is issued, so plan how your apps re-read them, as in managing roles across apps. - Do you need rules on single objects? Roles answer “may Jane publish posts?”, not “may Jane edit document 42?”. For that, pair your provider with a fine-grained authorization service. OpenFGA, an open-source CNCF incubating project based on Google’s Zanzibar, is one example: such services store relationships, like “Jane is an editor of document 42”, and answer checks against them. Amazon Verified Permissions does similar checks with Cognito tokens.
Where loginos fits
loginos is a hosted OpenID Connect provider for products that run on many domains, and roles are part of every platform. It fits when global roles are enough and you want them in every token without writing a hook.
Jane’s roles
Tap to try your own mix.
{ "sub": "9b1f6c2e-…", "preferred_username": "jane", "roles": [ "member" ], "permissions": [ "comments:write", "posts:read" ]}- Define permissions like
posts:publishand roles likeeditorin the console’s Roles tab, and mark the default roles that everyone who joins gets. - Read them without setup: the ID token, the token endpoint’s
userobject and/oauth/userinfoalways carryrolesandpermissions, whatever scopes you asked for. No setting, Action or hook is needed. - Change them from your server with
PUT /api/v1/users/{sub}/roles, which replaces the list. Blocking is separate:POST /api/v1/users/{sub}/blockstops sign-in on all your domains. - Apply them everywhere: roles belong to the platform and are shared by all of its domains.
{
"sub": "9b1f6c2e-5d1a-4b7e-9a51-0e6f3f6c1d2a",
"preferred_username": "jane",
"roles": ["editor", "member"],
"permissions": ["comments:write", "posts:publish", "posts:read"]
}A token shows the roles someone had at sign-in, so your server reads current ones from userinfo or the Management API. The roles guide and the claims reference have the details.
loginos is not the right fit for everyone. A platform has no organizations or tenants, so a person can’t be an admin in one customer workspace and a viewer in another unless your database records it. There are no webhooks and no SCIM, so changes aren’t pushed to your apps. If you need per-organization roles, look at Auth0, Clerk, WorkOS, Kinde, Logto or Zitadel.
Frequently asked questions
Does Auth0 include roles in the ID token?
No. Auth0 adds no roles by default, and its API setting only puts a permissions array in access tokens for that API. To get roles, write a post-login Action that copies event.authorization.roles into a custom claim with a namespaced name, such as https://example.com/roles, because roles is a restricted claim name.
How do I add roles to Firebase Auth?
Set them as custom claims from a trusted server with the Admin SDK, for example setCustomUserClaims(uid, { admin: true }). Each call replaces all of the user’s custom claims, so send the full set every time. The new claims appear only in a newly issued ID token, which the client can force with getIdToken(true).
Does Supabase Auth support roles and permissions?
Not as a built-in feature. The role claim in a Supabase token is the Postgres role, such as authenticated. For app roles, keep roles and permissions in your own tables, add a claim with a custom access token hook, and check it in row level security policies or your API.
Which providers give users different roles in different organizations?
Clerk, WorkOS and Kinde assign roles only inside organizations, and Zitadel assigns them per organization too. Auth0, with Organizations, and Logto offer both global and per-organization roles. Keycloak can attach roles to organization groups since version 26.7. Cognito, Firebase Auth, Supabase Auth and loginos have no organizations inside one user pool, so you keep that membership in your own database.
One account for every domain you run
loginos is an OpenID Connect provider with passkeys, a user pool shared by all of your domains, roles in every token, and account linking for the users you already have. Add your platform and its domains in a few minutes.
Keep reading
- Roles and permissionsHow do I put roles and permissions in a JWT?Add them as claims when the token is issued, usually a roles array and a permissions array that the issuer signs with the rest of the token. Before you trust them, verify the signature, issuer, audience and expiry, then check permissions rather than role names. Keep lifetimes short, because a token shows the roles someone had when it was issued. loginos puts both claims in every ID token.8 min read
- Roles and permissionsHow do I manage user roles across multiple apps?Keep roles in one central place, usually your identity provider, and have every app read them from there instead of keeping its own copy. Name permissions per app, like billing:invoices:refund, deliver them in tokens at sign-in, re-check them through an API, and offboard people by blocking their account once. In loginos, one platform’s roles apply on all of its domains.7 min read
- Choosing a providerWhat is a good alternative to Auth0?Good Auth0 alternatives include hosted services like Clerk, WorkOS AuthKit, Stytch, Descope and Kinde, and open-source servers you run yourself, like Keycloak, Zitadel, authentik, Ory and Logto. Firebase, Supabase and Amazon Cognito bundle sign-in with their platforms, and Auth.js or Better Auth keep it in your code. Choose by who runs it and how you would leave. loginos fits products on many domains.7 min read
- Choosing a providerWhat is the best authentication solution for Next.js?There is no single best authentication solution for Next.js; the right one depends on your situation. Clerk and Supabase Auth get a prototype or a social-login app running quickly. WorkOS, Auth0 and Clerk suit B2B apps that need organizations and SAML. Better Auth and Auth.js keep users in your own database, and loginos is a hosted OpenID Connect option for many domains that share one user pool.8 min read