---
title: Role management actions
description: Discover how to perform common actions that can be use to manage roles and permissions.
sidebar:
  order: 4
---

## Overview 


**SuperTokens** exposes a set of functions and APIs that you can use to have fine-grained control over roles and permissions.
Actions like listing roles, creating permissions, or checking which roles you assign are available through different SDK calls.

## Before you start

:::info[You can also perform most of the actions outlined on this page from the user management dashboard.]
To know more about how to use it check [the documentation](/post-authentication/dashboard/user-management)

:::

---

## Create a role

<DependentContent passive group="backend-language">
<ContentOption title="Dashboard" value="dashboard">
<img src="/docs-assets/img/dashboard/create-role.gif" alt="Create Role"/>
</ContentOption>
</DependentContent>

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function createRole() {
  const response = await UserRoles.createNewRoleOrAddPermissions("user", ["read"]);

  if (response.createdNewRole === false) {
    // The role already exists
  }
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func createRole() {
	resp, err := userroles.CreateNewRoleOrAddPermissions("user", []string{
		"read",
	}, nil)

	if err != nil {
		// TODO: Handle error
		return
	}
	if resp.OK.CreatedNewRole == false {
		// The role already exists
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions

async def create_role():
    res = await create_new_role_or_add_permissions("user", ["read"])
    if not res.created_new_role:
        # The role already existed
        pass

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions

def create_role():
    res = create_new_role_or_add_permissions("user", ["read"])
    if not res.created_new_role:
        # The role already existed
        pass

```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request PUT '<CORE_API_ENDPOINT>/recipe/role' \
--header 'api-key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
  "role": "user",
  "permissions": [
    "read"
  ]
}'

```
</Tab>
<Tab title="Dashboard" value="dashboard">

</Tab>
</CodeGroup>

---

## List roles

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function getAllRoles() {
  const roles: string[] = (await UserRoles.getAllRoles()).roles;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func getAllRoles() {
	response, err := userroles.GetAllRoles(nil)
	if err != nil {
		// TODO: Handle error
		return
	}
	_ = response.OK.Roles
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import get_all_roles

async def create_role():
	_ = (await get_all_roles()).roles

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import get_all_roles

def create_role():
	_ = get_all_roles().roles

```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request GET 'http://localhost:3567/recipe/roles' \
--header 'api-key: <YOUR_API_KEY>'
```
</Tab>
</CodeGroup>

---

## Delete a role

You can delete any role you have created, if the role you are trying to delete does not exist then this has no effect.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function deleteRole() {
  // Delete the user role
  const response = await UserRoles.deleteRole("user");

  if (!response.didRoleExist) {
    // There was no such role
  }
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func deleteRole() {
	// Delete the user role
	response, err := userroles.DeleteRole("user", nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.OK.DidRoleExist == false {
		// There was no such role
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import delete_role

async def delete_role_function():
    res = await delete_role("user")
    if res.did_role_exist:
        # The role actually existed
        pass

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import delete_role

def delete_role_function():
    res = delete_role("user")
    if res.did_role_exist:
        # The role actually existed
        pass

```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request POST 'http://localhost:3567/recipe/role/remove' \
--header 'api-key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
  "role": "admin"
}'
```
</Tab>
</CodeGroup>


---

## Add permissions

The SDK function only adds missing permissions and does not have any effect on permissions that are already assigned to a role.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function addPermissionForRole() {
  // Add the "write" permission to the "user" role
  await UserRoles.createNewRoleOrAddPermissions("user", ["write"]);
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func addPermissionForRole() {
	// Add the write permission to the user role
	_, err := userroles.CreateNewRoleOrAddPermissions("user", []string{"write"}, nil)
	if err != nil {
		// TODO: Handle error
		return
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import create_new_role_or_add_permissions


async def add_permission_for_role():
	await create_new_role_or_add_permissions("user", ["write"])

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import create_new_role_or_add_permissions


def add_permission_for_role():
	create_new_role_or_add_permissions("user", ["write"])

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

:::info[Multi Tenancy]

In a multi-tenant setup, roles, and permissions share across all tenants. This means that you can create a role and add permissions to it once, and reuse that role across any tenant in your app.

:::

---

## Remove permissions

To remove one or more permissions from a role, first create the role before you use this function.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function removePermissionFromRole() {
  // Remove the "write" permission to the "user" role
  const response = await UserRoles.removePermissionsFromRole("user", ["write"]);

  if (response.status === "UNKNOWN_ROLE_ERROR") {
    // No such role exists
  }
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func removePermissionFromRole() {
	// Remove the write permission to the user role
	response, err := userroles.RemovePermissionsFromRole("user", []string{"write"}, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.UnknownRoleError != nil {
		// No such role exists
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import remove_permissions_from_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

async def remove_permission_from_role_func():
	res = await remove_permissions_from_role("user", ["write"])
	if isinstance(res, UnknownRoleError):
		# No such role exists
		pass

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import remove_permissions_from_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

def remove_permission_from_role_func():
	res = remove_permissions_from_role("user", ["write"])
	if isinstance(res, UnknownRoleError):
		# No such role exists
		pass

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

---

## Get permissions by role

Get a list of all permissions assigned to a role.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function getPermissionsForRole() {
  const response = await UserRoles.getPermissionsForRole("user");

  if (response.status === "UNKNOWN_ROLE_ERROR") {
    // No such role exists
    return;
  }

  const permissions: string[] = response.permissions;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func getPermissionsForRole() {
	// const response = await UserRoles.getPermissionsForRole("user");
	response, err := userroles.GetPermissionsForRole("user", nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.UnknownRoleError != nil {
		// No such role exists
		return
	}

	_ = response.OK.Permissions
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import get_permissions_for_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

async def remove_permission_from_role():
	res = await get_permissions_for_role("user")
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	_ = res.permissions

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import get_permissions_for_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

def remove_permission_from_role():
	res = get_permissions_for_role("user")
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	_ = res.permissions

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

--- 

## Get roles by permission

Get a list of all the roles assigned a specific permission.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function getRolesWithPermission() {
  const response = await UserRoles.getRolesThatHavePermission("write");
  const roles: string[] = response.roles;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func getRolesWithPermission() {
	response, err := userroles.GetRolesThatHavePermission("write", nil)
	if err != nil {
		// TODO: Handle error
		return
	}
	_ = response.OK.Roles
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import get_roles_that_have_permission


async def get_roles_with_permission():
	res = await get_roles_that_have_permission("write")
	_ = res.roles

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import get_roles_that_have_permission


def get_roles_with_permission():
	res = get_roles_that_have_permission("write")
	_ = res.roles

```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>

---

## Assign roles to a user 


<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function addRoleToUser(userId: string) {
  const response = await UserRoles.addRoleToUser("public", userId, "user");

  if (response.status === "UNKNOWN_ROLE_ERROR") {
    // No such role exists
    return;
  }

  if (response.didUserAlreadyHaveRole === true) {
    // The user already had the role
  }
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func addRoleToUser(userId string) {
	response, err := userroles.AddRoleToUser("public", userId, "user", nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.UnknownRoleError != nil {
		// No such role exists
		return
	}

	if response.OK.DidUserAlreadyHaveRole {
		// The user already had the role
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import add_role_to_user
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError


async def add_role_to_user_func(user_id: str):
	role = "user"
	res = await add_role_to_user("public", user_id, role)
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	if res.did_user_already_have_role:
		# User already had this role
		pass
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import add_role_to_user
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError


def add_role_to_user_func(user_id: str):
	role = "user"
	res = add_role_to_user("public", user_id, role)
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	if res.did_user_already_have_role:
		# User already had this role
		pass

```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request PUT 'http://localhost:3567/recipe/user/role' \
--header 'api-key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
  "userId": "fa7a0841-b533-4478-95533-0fde890c3483",
  "role": "user"
}'
```
</Tab>
</CodeGroup>

## Assign roles to a session 

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import { UserRoleClaim, PermissionClaim } from "supertokens-node/recipe/userroles";
import { SessionContainer } from "supertokens-node/recipe/session";

async function addRolesAndPermissionsToSession(session: SessionContainer) {
  // we add the user's roles to the user's session
  await session.fetchAndSetClaim(UserRoleClaim);

  // we add the permissions of a user to the user's session
  await session.fetchAndSetClaim(PermissionClaim);
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims"
)

func addRolesAndPermissionsToSession(session sessmodels.SessionContainer) error {
	// we add the user's roles to the user's session
	err := session.FetchAndSetClaim(userrolesclaims.UserRoleClaim)
	if err != nil {
		return err
	}

	// we add the user's permissions to the user's session
	err = session.FetchAndSetClaim(userrolesclaims.PermissionClaim)
	if err != nil {
		return err
	}

	return nil
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim


async def add_roles_and_permissions_to_session(session: SessionContainer):
    # we add the user's roles to the user's session
    await session.fetch_and_set_claim(UserRoleClaim)

    # we add the user's permissions to the user's session
    await session.fetch_and_set_claim(PermissionClaim)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.session import SessionContainer
from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim


def add_roles_and_permissions_to_session(session: SessionContainer):
    # we add the user's roles to the user's session
	session.sync_fetch_and_set_claim(UserRoleClaim)
    
    # we add the user's permissions to the user's session
	session.sync_fetch_and_set_claim(PermissionClaim)
```
</ContentOption>
</DependentContent>
</Tab>
</CodeGroup>


:::info[Multi Tenancy]
Whilst roles and permissions share across apps, the association of roles to users is on a per-tenant level. If using SDK functions to add a role to a user, you can also pass in a `tenantId` to the function. This tells SuperTokens to add the role for that user for that tenant.

In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. You can fetch the user's `tenantId` from their current session, or from their user object (which you can fetch using their `userId`).

Note that if you associate a role to a user ID for a tenant, and that user ID doesn't actually belong to that tenant, then the operation still succeeds.
:::

---

## Remove role from a user and their sessions

You can remove roles from a user. The system removes the role you provide only if the user previously had that role.

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";
import { SessionContainer } from "supertokens-node/recipe/session";

async function removeRoleFromUserAndTheirSession(session: SessionContainer) {
  const response = await UserRoles.removeUserRole(session.getTenantId(), session.getUserId(), "user");

  if (response.status === "UNKNOWN_ROLE_ERROR") {
    // No such role exists
    return;
  }

  if (response.didUserHaveRole === false) {
    // The user was never assigned the role
  } else {
    // We also want to update the session of this user to reflect this change.
    await session.fetchAndSetClaim(UserRoles.UserRoleClaim);
    await session.fetchAndSetClaim(UserRoles.PermissionClaim);
  }
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
	"github.com/supertokens/supertokens-golang/recipe/userroles"
	"github.com/supertokens/supertokens-golang/recipe/userroles/userrolesclaims"
)

func removeRoleFromUserAndTheirSession(session sessmodels.SessionContainer) {
	response, err := userroles.RemoveUserRole(session.GetTenantId(), session.GetUserID(), "user", nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.UnknownRoleError != nil {
		// No such role exists
		return
	}

	if response.OK.DidUserHaveRole == false {
		// The user was never assigned the role
	} else {
		// We also want to update the session of this user to reflect this change.
		session.FetchAndSetClaim(userrolesclaims.UserRoleClaim)
		session.FetchAndSetClaim(userrolesclaims.PermissionClaim)
	}
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import remove_user_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError
from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim
from supertokens_python.recipe.session import SessionContainer

async def remove_role_from_user_and_their_session(session: SessionContainer):
    res = await remove_user_role(session.get_tenant_id(), session.get_user_id(), "user")
    if isinstance(res, UnknownRoleError):
        # No such role exists
        return

    if res.did_user_have_role == False:
        # The user was never assigned the role
        pass
    else:
        # We also want to update the session of this user to reflect this change.
        await session.fetch_and_set_claim(UserRoleClaim)
        await session.fetch_and_set_claim(PermissionClaim)
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import remove_user_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError
from supertokens_python.recipe.userroles import UserRoleClaim, PermissionClaim
from supertokens_python.recipe.session import SessionContainer

def remove_role_from_user_and_their_session(session: SessionContainer):
    res = remove_user_role(session.get_tenant_id(), session.get_user_id(), "user")
    if isinstance(res, UnknownRoleError):
        # No such role exists
        return

    if res.did_user_have_role == False:
        # The user was never assigned the role
        pass
    else:
        # We also want to update the session of this user to reflect this change.
        session.sync_fetch_and_set_claim(UserRoleClaim)
        session.sync_fetch_and_set_claim(PermissionClaim)
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request POST 'http://localhost:3567/recipe/user/role/remove' \
--header 'api-key: <YOUR_API_KEY>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
  "userId": "fa7a0841-b533-4478-95533-0fde890c3483",
  "role": "user"
}'
```
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
When using the multi-tenancy feature, in the previous snippets, only the user's role for the tenant they used to log in gets removed.
That's the one stored in the session.

You can pass in another tenant ID if you like, or call the function above for all the tenants that the user belongs to.
:::

---

## List the roles of a user

<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function getRolesForUser(userId: string) {
  const response = await UserRoles.getRolesForUser("public", userId);
  const roles: string[] = response.roles;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func getRolesForUser(userId string) {
	response, err := userroles.GetRolesForUser("public", userId, nil)
	if err != nil {
		// TODO: Handle error
		return
	}
	_ = response.OK.Roles
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import get_roles_for_user

async def get_roles_for_user_func(user_id: str):
	_ = (await get_roles_for_user("public", user_id)).roles
```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import get_roles_for_user

def get_roles_for_user_func(user_id: str):
	_ = get_roles_for_user("public", user_id).roles
```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request GET 'http://localhost:3567/recipe/user/roles?userId=fa7a0841-b533-4478-95533-0fde890c3483' \
--header 'api-key: <YOUR_API_KEY>'
```
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. You can fetch the user's `tenantId` from their current session, or from their user object (which you can fetch using their `userId`).
:::

---

## List the users of a role


<CodeGroup group="backend-language">
<Tab title="Node.js" value="nodejs">
```tsx
import UserRoles from "supertokens-node/recipe/userroles";

async function getUsersThatHaveRole(role: string) {
  const response = await UserRoles.getUsersThatHaveRole("public", role);

  if (response.status === "UNKNOWN_ROLE_ERROR") {
    // No such role exists
    return;
  }

  const users: string[] = response.users;
}
```
</Tab>
<Tab title="Go" value="go">
```go
import (
	"github.com/supertokens/supertokens-golang/recipe/userroles"
)

func getUsersThatHaveRole(role string) {
	response, err := userroles.GetUsersThatHaveRole("public", role, nil)
	if err != nil {
		// TODO: Handle error
		return
	}

	if response.UnknownRoleError != nil {
		// No such role exists
		return
	}

	_ = response.OK.Users
}
```
</Tab>
<Tab title="Python" value="python">
<DependentContent group="python-io-style" label="I/O style">
<ContentOption title="Asyncio" value="asyncio">
```python
from supertokens_python.recipe.userroles.asyncio import get_users_that_have_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

async def get_users_that_have_role_func(role: str):
	res = await get_users_that_have_role("public", role)
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	_ = res.users

```
</ContentOption>
<ContentOption title="Syncio" value="syncio">
```python
from supertokens_python.recipe.userroles.syncio import get_users_that_have_role
from supertokens_python.recipe.userroles.interfaces import UnknownRoleError

def get_users_that_have_role_func(role: str):
	res = get_users_that_have_role("public", role)
	if isinstance(res, UnknownRoleError):
		# No such role exists
		return

	_ = res.users

```
</ContentOption>
</DependentContent>
</Tab>
<Tab title="cURL" value="curl">
```bash
curl --location --request GET 'http://localhost:3567/recipe/role/users?role=user' \
--header 'api-key: <YOUR_API_KEY>'
```
</Tab>
</CodeGroup>

:::info[Multi Tenancy]
In the code examples above, the `"public"` `tenantId` appears, which is the default `tenantId` for users. This returns the list of users that have that role in the `"public"` tenant.

You can also pass in a different tenant ID, or call the function in a loop with all the tenants that exist in your app.
:::


---

## See also

<CardGroup cols={3}>
  <Card title="Claim validation" href="/additional-verification/session-verification/claim-validation" />
  <Card title="Protect backend routes" href="/additional-verification/session-verification/protect-api-routes" />
  <Card title="Protect frontend routes" href="/additional-verification/session-verification/protect-frontend-routes" />
</CardGroup>
