# Get a bearer token with user roles via the /oauth/token API

**URL:** <https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148>\
**Category:** Get Help\
**Tags:** management-api, roles\
**Created:** [April 8, 2025, 9:03am UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148 "2025-04-08T09:03:59Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![pdaj-atl](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/pdaj-atl/32/74110_2.png) [@pdaj-atl](https://community.auth0.com/u/pdaj-atl)\
**Post date:** [April 8, 2025, 9:03am UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/1 "2025-04-08T09:03:59Z")

</div>

My standard login process via the /authorize url is working fine and I have set it up to include user roles in the returned token with the following action:

```auto
exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://blah.blah.com'; // Use a custom namespace
  // Check if event.authorization and roles exist
  const assignedRoles = event.authorization && event.authorization.roles 
    ? event.authorization.roles 
    : [];

  // Set roles only if they exist
  if (assignedRoles.length > 0) {
    api.idToken.setCustomClaim(`${namespace}/roles`, assignedRoles);
    api.accessToken.setCustomClaim(`${namespace}/roles`, assignedRoles);
  }
};

```

Now for testing I want to be able to get a token for specific user types without requiring user input. To do this I believe the correct way is to use the /oauth/token endpoint. I’ve tried this with the “client\_credentials” grant type:

```auto
async fn get_auth_token_cc() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": &format!("{}/api/v2/", domain),
            "grant_type": "client_credentials",
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
        }))
        .send()
        .await
        .expect("Failed to get token");

    info!("{:?}", res);
    let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
    token.access_token
}

```

This succeeds but provides a token without any user or user role information.

I then thought that I needed to create a custom API for my Application and do an endpoint request with the “password” grant type:

```auto

async fn get_auth_token() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "grant_type": "password",
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": std::env::var("AUTH0_AUDIENCE").expect("AUTH0_AUDIENCE not set"),
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
            "scope": "openid profile email",
            "realm": "Username-Password-Authentication"
        }))
        .send()
        .await
        .expect("Failed to get token");

    info!("{:?}", res);
    let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
    token.access_token
}

```

However this returns a 500 “Authorization server not configured with default connection”. Here is the full response:

```auto
{
   "url":"https://dev-gdmpjq3p28gmc875.uk.auth0.com/oauth/token",
   "status":500,
   "headers":{
      "date":"Mon, 07 Apr 2025 20:04:44 GMT",
      "content-type":"application/json",
      "content-length":"107",
      "connection":"keep-alive",
      "cf-ray":"92cc22beddcd6519-LHR",
      "cf-cache-status":"DYNAMIC",
      "cache-control":"private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, no-transform",
      "set-cookie":"did=s%3Av0%3A3c8852bf-20e3-4269-9159-26ad7f477809.L7xzF7%2FmbWo7pKdPtNXibEcWkb1DrVet6cbR4dpK84k; Path=/; Expires=Wed, 08 Apr 2026 02:04:44 GMT; HttpOnly; Secure; SameSite=None",
      "set-cookie":"did_compat=s%3Av0%3A3c8852bf-20e3-4269-9159-26ad7f477809.L7xzF7%2FmbWo7pKdPtNXibEcWkb1DrVet6cbR4dpK84k; Path=/; Expires=Wed, 08 Apr 2026 02:04:44 GMT; HttpOnly; Secure",
      "strict-transport-security":"max-age=31536000; includeSubDomains",
      "vary":"Origin",
      "x-auth0-l":"0.033",
      "x-auth0-requestid":"09abe69cf770170cd8ed",
      "x-content-type-options":"nosniff",
      "x-ratelimit-limit":"300",
      "x-ratelimit-remaining":"299",
      "x-ratelimit-reset":"1744056345",
      "server":"cloudflare",
      "alt-svc":"h3=\":443\"; ma=86400"
   }
}

```

Do I have the correct method? If so, is there a setting I need to configure on the dashboard to get this to work?

Thanks!

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [April 8, 2025, 6:27pm UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/3 "2025-04-08T18:27:45Z")

</div>

Hi @pdaj-atl

Welcome to the Auth0 Community!

Once you have assigned roles to the user and they are visible on the Dashboard under **User Managemenr → Users → Select User → Roles** they should be visible in the ID Token after they have been set as custom claims using your action.

I have tested this using Postman and after decoding the JWT on [jwt.io](http://jwt.io) this is the result:

```auto
{
  "https://blah.blah.com/roles": [
    "Secondary Test",
    "Test"
  ],
  "email": "{test_email}}",
  "email_verified": false,
  "nickname": "{{nickname}}",
  "name": "{{name}}",
  "picture": "{{picture_url}}",
  "updated_at": "2025-04-08T18:14:34.260Z",
  "iss": "{{auth0_domain}}",
  "aud": "{{audience}}",
  "sub": "{{user_id}}",
  "iat": 1744136075,
  "exp": 1744172075
}

```

I have tested the endpoint using Postman and this is the configuration I have used:

 ![image](https://global.discourse-cdn.com/auth0/original/3X/f/7/f70176e0acff9af4c927613ffa7542428b0635a1.png)

The only differences that I can spot is that you are using the `grant_type` of `password` not `password-realm`, even though you are declaring the realm in your body, and that you are using application/json whereas I am using the urlencoded since I am using postman.

Could you please try switching to`password-realm` for the grant type? Make sure to enable the grant for `Password` inside the application that you are using.

Let me know if this was helpful or if you have any other questions!

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![pdaj-atl](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/pdaj-atl/32/74110_2.png) [@pdaj-atl](https://community.auth0.com/u/pdaj-atl)\
**Post date:** [April 9, 2025, 9:36am UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/4 "2025-04-09T09:36:40Z")

</div>

Hi Nik,  
Thanks for your response. I’m still having problems. I’ve tried to recreate your exact call:

```auto
async fn get_auth_token_pw() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "grant_type": "password-realm",
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": &format!("{}/api/v2/", domain),
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
            "realm": "Username-Password-Authentication",
            "scope": "openid email profile read:current_user offline_access",
        }))
        .send()
        .await
        .expect("Failed to get token");

    info!("{:#?}", res);

    if res.status().is_success() {
        let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
        info!("{:#?}", token);
        token.access_token
    } else {
        "NO TOKEN".to_owned()
    }
}

```

And using this gives:

```auto
Response {
    url: "https://<domain>/oauth/token",
    status: 403,
    headers: {
        "date": "Wed, 09 Apr 2025 09:16:55 GMT",
        "content-type": "application/json",
        "content-length": "173",
        "connection": "keep-alive",
        "cf-ray": "92d8e88cbb5aa690-LHR",
        "cf-cache-status": "DYNAMIC",
        "cache-control": "private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0, no-transform",
        "set-cookie": "did=s%3Av0%3Afa6055a6-079f-4cc9-9695-7e8a70b20455.aX2yPsBAXnsL50WcvSQDg3xz3kdgLdouuKMVkMKDRDM; Path=/; Expires=Thu, 09 Apr 2026 15:16:55 GMT; HttpOnly; Secure; SameSite=None",
        "set-cookie": "did_compat=s%3Av0%3Afa6055a6-079f-4cc9-9695-7e8a70b20455.aX2yPsBAXnsL50WcvSQDg3xz3kdgLdouuKMVkMKDRDM; Path=/; Expires=Thu, 09 Apr 2026 15:16:55 GMT; HttpOnly; Secure",
        "strict-transport-security": "max-age=31536000; includeSubDomains",
        "vary": "Origin",
        "x-auth0-l": "0.030",
        "x-auth0-requestid": "5e90fd85224c912a9366",
        "x-content-type-options": "nosniff",
        "x-ratelimit-limit": "300",
        "x-ratelimit-remaining": "299",
        "x-ratelimit-reset": "1744190276",
        "server": "cloudflare",
        "alt-svc": "h3=\":443\"; ma=86400",
    },
}

```

Using the “client\_credentials” grant type with this code:

```auto
async fn get_auth_token_cc() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "grant_type": "client_credentials",
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": &format!("{}/api/v2/", domain),
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
        }))
        .send()
        .await
        .expect("Failed to get token");

    info!("{:#?}", res);

    if res.status().is_success() {
        let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
        info!("{:#?}", token);
        token.access_token
    } else {
        "NO TOKEN".to_owned()
    }
}

```

This “works” in the sense that the endpoint succeeds:

```auto
Response {
    url: "https://<domain>/oauth/token",
    status: 200,
    headers: {
        "date": "Wed, 09 Apr 2025 09:16:55 GMT",
        "content-type": "application/json",
        "transfer-encoding": "chunked",
        "connection": "keep-alive",
        "cf-ray": "92d8e88dc96271c6-LHR",
        "cf-cache-status": "DYNAMIC",
        "cache-control": "no-store",
        "set-cookie": "did=s%3Av0%3A85601f5b-5e95-453a-8a2b-129aff7f650f.UCChErkp%2Fwd2pf761ZCLbujoVxYzBlqIs2dbEjYlO8E; Path=/; Expires=Thu, 09 Apr 2026 15:16:55 GMT; HttpOnly; Secure; SameSite=None",
        "set-cookie": "did_compat=s%3Av0%3A85601f5b-5e95-453a-8a2b-129aff7f650f.UCChErkp%2Fwd2pf761ZCLbujoVxYzBlqIs2dbEjYlO8E; Path=/; Expires=Thu, 09 Apr 2026 15:16:55 GMT; HttpOnly; Secure",
        "strict-transport-security": "max-age=31536000; includeSubDomains",
        "vary": "Accept-Encoding, Origin",
        "pragma": "no-cache",
        "x-auth0-dl": "21",
        "x-auth0-l": "0.088",
        "x-auth0-requestid": "1fb853675396699dab70",
        "x-content-type-options": "nosniff",
        "x-ratelimit-limit": "300",
        "x-ratelimit-remaining": "298",
        "x-ratelimit-reset": "1744190276",
        "server": "cloudflare",
        "alt-svc": "h3=\":443\"; ma=86400",
    },
}

```

But the user information is not in the decoded JWT:

```auto
Claims {
    sub: "FFerjBdGic0fN5zC7bHqPHfL65anuwBY@clients",
    exp: 1744276615,
    email: None,
    name: None,
    roles: None,
}

```

My conclusion is that “client\_credentials” grant type can’t provide a token with the user information and “password-realm” grant type is for some reason blocked for me. I have looked through the dashboard settings but can’t see anything obvious. My application does have the “Password” grant type ticked in Advanced settings.

---

<div class="post-metadata">

**Author:** ![nik.baleca](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/nik.baleca/32/68749_2.png) [@nik.baleca](https://community.auth0.com/u/nik.baleca)\
**Post date:** [April 9, 2025, 3:08pm UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/5 "2025-04-09T15:08:44Z")

</div>

Hi again,

Indeed, the `client_credentials` grant will not return an ID Token.  
However, could you please try to use `http://auth0.com/oauth/grant-type/password-realm` instead of just` password-realm`.

Alternatively, please try the following:

- Navigate to your dashboard
- On the left menu, click on Setting
- Scroll down to “API Authorization Settings”
- Enter `Username-Password-Authentication` in the “Default Directory” input
- Hit save

After you have done this, try running your initial code:

```auto
async fn get_auth_token() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "grant_type": "password",
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": std::env::var("AUTH0_AUDIENCE").expect("AUTH0_AUDIENCE not set"),
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
            "scope": "openid profile email",
            "realm": "Username-Password-Authentication"
        }))
        .send()
        .await
        .expect("Failed to get token");

    info!("{:?}", res);
    let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
    token.access_token
}

```

Please let me know if any of the proposed solutions work for you!

Kind Regards,  
Nik

---

<div class="post-metadata">

**Author:** ![pdaj-atl](https://sea1.discourse-cdn.com/auth0/user_avatar/community.auth0.com/pdaj-atl/32/74110_2.png) [@pdaj-atl](https://community.auth0.com/u/pdaj-atl)\
**Post date:** [April 9, 2025, 5:13pm UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/6 "2025-04-09T17:13:33Z")

</div>

Hi Nik,  
Using the full url for the “grant\_type” solved the problem. Thank you so much! I’ll post the working code here in case it turns out to be useful to someone else:

```auto
async fn get_auth_token() -> String {
    let client = reqwest::Client::new();
    let domain = std::env::var("DOMAIN").expect("DOMAIN not set");
    let res = client
        .post(&format!("{}/oauth/token", domain))
        .header("content-type", "application/json")
        .json(&serde_json::json!({
            "grant_type": "http://auth0.com/oauth/grant-type/password-realm",
            "client_id": std::env::var("CLIENT_ID").expect("CLIENT_ID not set"),
            "client_secret": std::env::var("CLIENT_SECRET").expect("CLIENT_SECRET not set"),
            "audience": &format!("{}/api/v2/", domain),
            "username": std::env::var("AUTH0_USER_UN").expect("AUTH0_USER_UN not set"),
            "password": std::env::var("AUTH0_USER_PW").expect("AUTH0_USER_PW not set"),
            "realm": "Username-Password-Authentication",
            "scope": "openid email profile read:current_user offline_access",
        }))
        .send()
        .await
        .expect("Failed to get token");

    if res.status().is_success() {
        let token: Auth0TokenResponse = res.json().await.expect("Invalid token response");
        token.access_token
    } else {
        "NO TOKEN".to_owned()
    }
}

```

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/auth0/original/3X/b/5/b560f266932fcce5d57f09a6595bd50518cae3f3.jpeg) [@system](https://community.auth0.com/u/system)\
**Post date:** [April 23, 2025, 5:14pm UTC](https://community.auth0.com/t/get-a-bearer-token-with-user-roles-via-the-oauth-token-api/185148/7 "2025-04-23T17:14:30Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
