apps/docs/content/guides/integrate/retrieve-user-roles.mdx
<TerminologyUpdate newTerm="Role Assignment" oldTerms={["User Grant", "Authorization"]} />
This guide explains all the possible ways of retrieving user roles across different organizations and projects using ZITADEL's APIs.
User role assignments or authorizations refer to the roles that are assigned to a user. These terms are used interchangeably to mean the roles assigned to the user, e.g., the ZITADEL Console refers to the pairing of roles and users as role assignments, whereas the APIs refer to them as authorizations or user grants. This guide will use the term roles for application-specific roles (e.g., admin, accountant, employee, hr, etc.) and ZITADEL-specific manager roles (e.g., IAM_OWNER, ORG_OWNER, PROJECT_OWNER, etc.).
Roles are critical to managing permissions in a single-tenant or multi-tenant application. It can, however, be tricky to retrieve them, especially when spanning multiple organizations and projects.
Users or service accounts can be assigned roles. You can do this via the ZITADEL Management Console or the ZITADEL APIs. As mentioned earlier, there are two types of roles in ZITADEL. You can have your own application-specific roles, and alternatively, ZITADEL also has administrator roles, such as ORG_OWNER and IAM_OWNER.
Follow the links below to assign roles to your users.
Roles can be requested via our auth and management APIs, from userinfo endpoint or ID token. Currently, administrator roles cannot be directly included in the token. You will need to use the ZITADEL APIs to retrieve them.
You must first of all generate a token for the user. For users, the typical approach involves using a front-end application and logging in through the browser or device. An access token will be returned after they log in successfully. A service account will use a script or other program to generate a token using the JWT profile or client credentials grant types.
How to generate a token:
To access role information via the token, you must include the right audience and the necessary role claims in the scope and/or select the required role settings in the ZITADEL management console before requesting the token.
An important concept in OpenID Connect (OIDC) is the 'audience' (aud) claim, which is part of the token payload. The aud claim identifies who or what this token is intended for. If the recipient (e.g., a resource server) does not identify itself with a value in the aud claim when this claim is present, then the token must be rejected.
The audience is essential in multi-tier systems, where you may authenticate with one application (in one project) but access resources from another application (in a different project) or when you are accessing ZITADEL’s management APIs. Without the correct audience in your token, you will run into errors, such as the ‘Invalid audience’ error in ZITADEL.
You can determine the audience in two ways:
1. Use the explicit scope for ZITADEL to access only ZITADEL APIs:
If your application needs to access ZITADEL's APIs (for example, to pull a list of all users), follow this steps:
urn:zitadel:iam:org:project:id:zitadel:aud to the authentication request when authenticating the user. Now, the application can make calls to ZITADEL's API without running into an ‘Invalid audience’ error.2. Include the project id of the ZITADEL project in the scope for accessing the ZITADEL APIs or anything else:
Let's assume you have a frontend application and a backend application under different projects. Here's how to add the correct audience:
urn:zitadel:iam:org:project:id:{projectId}:aud, replacing {projectId} with the project ID of your backend application.And you can also use the same to access the ZITADEL APIs.
If you need user roles returned from the userinfo endpoint, you must select the ’Assert Roles on Authentication’ checkbox in your project under general settings.
If you need them included in your ID Token, select ’User Roles Inside ID Token’ in application settings. This has to be set in your applications as this is dependent on your application type. Navigate to your application and select this setting.
Alternatively, you can include the claims urn:iam:org:project:roles or/and urn:zitadel:iam:org:projects:roles in your scope to achieve the same as above.
To determine the roles assigned to a user, you have two options:
urn:zitadel:iam:org:project:{projectId}:roles) is included in the token when you authenticate. The roles assigned to the user will then be part of the token’s payload.The user info endpoint is ${CUSTOM_DOMAIN}/oidc/v1/userinfo.
This endpoint will return information about the authenticated user.
Send the access token of the user as Bearer Token in the Authorization header:
cURL Request:
curl --request GET \
--url ${CUSTOM_DOMAIN}/oidc/v1/userinfo
--header 'Authorization: Bearer <TOKEN>'
If the access token is valid, the information about the user (depending on the granted scopes) is returned. Check the Claims page for more details.
Sample responses:
1. Scope used: openid email profile urn:zitadel:iam:org:project:id:zitadel:aud
Sample response:
{
"email": "[email protected]",
"email_verified": true,
"family_name": "Wallace",
"gender": "male",
"given_name": "David",
"locale": "en",
"name": "David Wallace",
"nickname": "David",
"preferred_username": "david.wallace",
"sub": "223427827918176513",
"updated_at": 1689669364,
"urn:zitadel:iam:org:project:223281986649719041:roles": {
"cfo": {
"223281939119866113": "corporate.user-authorizations-io8epz.zitadel.cloud"
},
"corporate member": {
"223279178798072065": "org-a.user-authorizations-io8epz.zitadel.cloud",
"223279223391912193": "org-b.user-authorizations-io8epz.zitadel.cloud"
}
},
"urn:zitadel:iam:org:project:roles": {
"cfo": {
"223281939119866113": "corporate.user-authorizations-io8epz.zitadel.cloud"
},
"corporate member": {
"223279178798072065": "org-a.user-authorizations-io8epz.zitadel.cloud",
"223279223391912193": "org-b.user-authorizations-io8epz.zitadel.cloud"
}
}
}
This request can be tested out in the following way:
2. Scope used: openid email profile urn:zitadel:iam:org:project:id:{projectId}:aud urn:iam:org:project:roles urn:zitadel:iam:org:projects:roles
Sample response:
{
"email": "[email protected]",
"email_verified": true,
"family_name": "Wallace",
"gender": "male",
"given_name": "David",
"locale": "en",
"name": "David Wallace",
"nickname": "David",
"preferred_username": "david.wallace",
"sub": "223427827918176513",
"updated_at": 1689669364,
"urn:zitadel:iam:org:project:223281986649719041:roles": {
"cfo": {
"223281939119866113": "corporate.user-authorizations-io8epz.zitadel.cloud"
},
"corporate member": {
"223279178798072065": "org-a.user-authorizations-io8epz.zitadel.cloud",
"223279223391912193": "org-b.user-authorizations-io8epz.zitadel.cloud"
}
},
"urn:zitadel:iam:org:project:roles": {
"cfo": {
"223281939119866113": "corporate.user-authorizations-io8epz.zitadel.cloud"
},
"corporate member": {
"223279178798072065": "org-a.user-authorizations-io8epz.zitadel.cloud",
"223279223391912193": "org-b.user-authorizations-io8epz.zitadel.cloud"
}
}
}
This request can be tested out in the following way:
If your application requires a custom role structure, ZITADEL actions allow you to customize your claims.
<details open="open"> <summary>Example on github</summary>https://github.com/zitadel/actions/blob/main/examples/custom_roles.js
Now we will use the auth API to retrieve roles from a logged-in user using the user’s token
The base URL is: https://${CUSTOM_DOMAIN}/auth/v1
Let’s start with a user who has multiple roles in different organizations in a multi-tenanted setup. You can use the logged-in user’s token or the service account’s token to retrieve the roles assigned to this user using the APIs listed under user authorizations/grants in the auth API.
Scope used: openid urn:zitadel:iam:org:project:id:zitadel:aud
Returns a list of roles for the authenticated user and for the requesting project (based on the token).
URL: https://${CUSTOM_DOMAIN}/auth/v1/permissions/me/_search
cURL request:
curl -L -X POST 'https://${CUSTOM_DOMAIN}/auth/v1/permissions/me/_search' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>'
Sample response:
{
"result": [
"cfo"
]
}
Returns a list of permissions the authenticated user has in ZITADEL based on the administrator roles the user has. (e.g: ORG_OWNER = org.read, org.write, ...).
This request can be used if you are building a management UI. For instance, if the UI is managing users, you can show the management functionality based on the permissions the user has. Here’s an example: if the user has user.read and user.write permission you can show the edit buttons, if the user only has user.read permission, you can hide the edit buttons.
URL: https://${CUSTOM_DOMAIN}/auth/v1/permissions/zitadel/me/_search
cURL Request:
curl -L -X POST 'https://${CUSTOM_DOMAIN}/auth/v1/permissions/zitadel/me/_search' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>'
Sample result:
{
"result": [
"org.read",
"user.read",
"user.global.read",
"user.write",
"user.delete",
"user.grant.read",
"user.grant.write",
"user.grant.delete",
"user.membership.read",
"policy.read",
"project.read",
"project.role.read",
"org.member.read",
"org.idp.read",
"org.action.read",
"org.flow.read",
"project.member.read",
"project.app.read",
"project.grant.read",
"project.grant.member.read",
"project.grant.user.grant.read",
"project.read:self",
"project.create"
]
}
Returns a list of roles the authenticated user has been assigned. Role assignments (referred to as user grants in the APIs) consist of an organization, a project, and roles.
URL: https://${CUSTOM-DOMAIN}/auth/v1/usergrants/me/_search
cURL request:
curl -L -X POST 'https://${CUSTOM_DOMAIN}/auth/v1/usergrants/me/_search' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
--data-raw '{
"query": {
"offset": "0",
"limit": 100,
"asc": true
}
}'
Sample result:
{
"details": {
"totalResult": "3",
"processedSequence": "339",
"viewTimestamp": "2023-07-19T09:20:34.371331Z"
},
"result": [
{
"orgId": "223279178798072065",
"projectId": "223281986649719041",
"userId": "223427827918176513",
"roles": [
"corporate member"
],
"orgName": "Org A",
"grantId": "223428842084106497",
"details": {
"sequence": "296",
"creationDate": "2023-07-18T08:46:07.692435Z",
"changeDate": "2023-07-18T08:46:07.692435Z",
"resourceOwner": "223279178798072065"
},
"orgDomain": "org-a.user-authorizations-io8epz.zitadel.cloud",
"projectName": "HR",
"projectGrantId": "223282340514758913",
"roleKeys": [
"corporate member"
],
"userType": "TYPE_HUMAN"
},
{
"orgId": "223279223391912193",
"projectId": "223281986649719041",
"userId": "223427827918176513",
"roles": [
"corporate member"
],
"orgName": "Org B",
"grantId": "223428980244480257",
"details": {
"sequence": "298",
"creationDate": "2023-07-18T08:47:30.015324Z",
"changeDate": "2023-07-18T08:47:30.015324Z",
"resourceOwner": "223279223391912193"
},
"orgDomain": "org-b.user-authorizations-io8epz.zitadel.cloud",
"projectName": "HR",
"projectGrantId": "223282930787549441",
"roleKeys": [
"corporate member"
],
"userType": "TYPE_HUMAN"
},
{
"orgId": "223281939119866113",
"projectId": "223281986649719041",
"userId": "223427827918176513",
"roles": [
"cfo"
],
"orgName": "Corporate",
"grantId": "223428420858544385",
"details": {
"sequence": "293",
"creationDate": "2023-07-18T08:41:56.649257Z",
"changeDate": "2023-07-18T08:44:33.094117Z",
"resourceOwner": "223281939119866113"
},
"orgDomain": "corporate.user-authorizations-io8epz.zitadel.cloud",
"projectName": "HR",
"roleKeys": [
"cfo"
],
"userType": "TYPE_HUMAN"
}
]
}
Now we will use the management API to retrieve user roles under an admin user.
The base URL is: https://${CUSTOM_DOMAIN}/management/v1
In APIs listed under user grants in the management API, you will see that you can use the management API to retrieve and modify user grants. The two API paths that we are interested in to fetch user roles are given below.
Scope used: openid urn:zitadel:iam:org:project:id:zitadel:aud
Returns a list of user roles that match the search queries. A user with administrator permissions will call this API and will also have to reside in the same organization as the user.
URL: https://${CUSTOM_DOMAIN}/management/v1/users/grants/_search
cURL request:
curl -L -X POST 'https://${CUSTOM_DOMAIN}/management/v1/users/grants/_search' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>' \
--data '{
"query": {
"offset": "0",
"limit": 100,
"asc": true
},
"queries": [
{
"user_id_query": {
"user_id": "223427827918176513"
}
}
]
}
Sample result:
{
"details": {
"totalResult": "1",
"processedSequence": "342",
"viewTimestamp": "2023-07-19T11:24:58.769023Z"
},
"result": [
{
"id": "223428420858544385",
"details": {
"sequence": "293",
"creationDate": "2023-07-18T08:41:56.649257Z",
"changeDate": "2023-07-18T08:44:33.094117Z",
"resourceOwner": "223281939119866113"
},
"roleKeys": [
"cfo"
],
"state": "USER_GRANT_STATE_ACTIVE",
"userId": "223427827918176513",
"userName": "david.wallace",
"firstName": "David",
"lastName": "Wallace",
"email": "[email protected]",
"displayName": "David Wallace",
"orgId": "223281939119866113",
"orgName": "Corporate",
"orgDomain": "corporate.user-authorizations-io8epz.zitadel.cloud",
"projectId": "223281986649719041",
"projectName": "HR",
"preferredLoginName": "david.wallace",
"userType": "TYPE_HUMAN"
}
]
}
Returns a user grant per ID. A user grant is a role a user has for a specific project and organization.
URL: https://${CUSTOM_DOMAIN}/management/v1/users/:userId/grants/:grantId
cURL request:
curl -L -X GET 'https://${CUSTOM_DOMAIN}/management/v1/users/:userId/grants/:grantId' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <TOKEN>'
The process of retrieving a user's roles involves understanding the audience scope, getting a token, and accessing the correct API endpoints based on your requirement. Following these steps will help efficiently manage roles in single and multi-tenant applications.