Migrate to Management API Endpoints with Access Tokens

Using ID tokens to call Management API endpoints is being deprecated. You must use access tokens. The grace period for this migration started on March 31, 2018.

After you complete your migration to access tokens, turn off the Allow ID Tokens for Management API v2 Authentication toggle in the Dashboard.

If you use ID tokens to call any of the following endpoints, then you are affected by this migration. These endpoints can now accept regular access tokens. Nothing else changes in how the endpoints work. You should expect the same request and response schemas and only need to update the token that you use for authorization.

Endpoints affected

Endpoint Use Case
GET /api/v2/users/{id} Retrieve a user's information
GET /api/v2/users/{id}/enrollments Retrieve all Guardian MFA enrollments for a user
PATCH /api/v2/users/{id} Update a user's information
DELETE /api/v2/users/{id}/multifactor/{provider} Delete the MFA provider settings for a user
POST /api/v2/device-credentials Create a public key for a device
DELETE /api/v2/device-credentials/{id} Delete a device credential
POST/api/v2/users/{id}/identities Link user accounts from various identity providers
DELETE /api/v2/users/{id}/identities/{provider}/{user_id} Unlink user accounts

Actions

Scope changes

The actions you can perform with the Management API depend on the scopes that your access token contains. With this migration, you can either get a limited access token that can update only the logged-in user's data or an access token that can update the data of any user. In the following matrix, you can see the scopes that your token needs to have per case and per endpoint.

For example, if you get an access token that contains the scope read:users, you can retrieve the data of any user using the GET /api/v2/users/{id} endpoint. However, if your token contains the scope read:current_user, you can only retrieve the information of the currently logged-in user (the one that the token was issued for).

Endpoint Scope for current user Scope for any user
GET /api/v2/users/{id} read:current_user read:users
GET /api/v2/users/{id}/enrollments read:current_user read:users
POST/api/v2/users/{id}/identities update:current_user_identities update:users
DELETE /api/v2/users/{id}/identities/{provider}/{user_id} update:current_user_identities update:users
PATCH /api/v2/users/{id} update:current_user_metadata update:users
PATCH /api/v2/users/{id} create:current_user_metadata update:users
DELETE /api/v2/users/{id}/multifactor/{provider} delete:current_user_metadata update:users
POST /api/v2/device-credentials create:current_user_device_credentials create:device_credentials
DELETE /api/v2/device-credentials/{id} delete:current_user_device_credentials delete:device_credentials

Get access tokens

Auth0 has changed how you get a token for the previously mentioned endpoints. There are several variations on how you authenticate a user and get tokens, depending on the technology and the OAuth 2.0 flow you use to authenticate:

  • SPA running in a browser: Use the Authorization endpoint.

  • Web app running on a server, a mobile app, a server process, or a highly trusted app: Use the Token endpoint.

  • Cross-authentication: Use embedded Lock or auth0.js to authenticate users when the requests come from different domains.

Authorization endpoint

In this section, we will use an example to show the differences in how you get a token with the Authorization endpoint. Keep in mind that no matter which endpoint you want to migrate, the changes are the same, the only thing that differs is the scopes that you specify in the request.

In the example below, you use the GET User by ID endpoint to retrieve the full profile information of the logged-in user. To do so, first, we will authenticate the user using the Implicit grant and retrieve the token(s). Below you can see an implementation of the old approach that gets an ID Token and then uses it to call the endpoint.

to configure this snippet with your account

    https://YOUR_DOMAIN/authorize?
      scope=openid
      &response_type=id_token
      &client_id=YOUR_CLIENT_ID
      &redirect_uri=https://YOUR_APP/callback
      &nonce=NONCE
      &state=OPAQUE_VALUE

In the example below, you can see the new approach that gets an access token.

to configure this snippet with your account

    https://YOUR_DOMAIN/authorize?
      audience=https://YOUR_DOMAIN/api/v2/
      &scope=read:current_user
      &response_type=token%20id_token
      &client_id=YOUR_CLIENT_ID
      &redirect_uri=https://YOUR_APP/callback
      &nonce=NONCE
      &state=OPAQUE_VALUE

To get an access token that can access the Management API:

  • Set the audience to https://YOUR_DOMAIN/api/v2/

  • Ask for the scope ${scope}

  • Set the response_type to id_token token so Auth0 will send both an ID token and an access token

If you decode the received access token and review its contents you will see the following:

    {
      "iss": "https://YOUR_DOMAIN/",
      "sub": "auth0|5a620d29a840170a9ef43672",
      "aud": "https://YOUR_DOMAIN/api/v2/",
      "iat": 1521031317,
      "exp": 1521038517,
      "azp": "YOUR_CLIENT_ID",
      "scope": "${scope}"
    }

Notice that aud is set to your tenant's API URI, scope is set to ${scope}, and sub is set to the user ID of the logged-in user.

Once you have the access token you can use it to call the endpoint. This part remains the same, nothing else changes in the request except for the value you use as Bearer token. The response remains also the same.

Token endpoint

In this section, we will use an example to show the differences in how you get a token with the Token endpoint. Keep in mind though that no matter which endpoint you want to migrate, the changes are the same, the only thing that differs is the scopes that you specify in the request.

In the example below, you want to use the GET User by ID endpoint to retrieve the full profile information of the logged-in user. First, authenticate the user using the Password Exchange grant and then retrieve the token(s). Below you can see an implementation of the old approach that gets an ID Token (and then uses it to call the endpoint).

to configure this snippet with your account

    POST https://YOUR_DOMAIN/oauth/token
    Content-Type: application/x-www-form-urlencoded
    {
      "grant_type": "password",
      "username": "USERNAME",
      "password": "PASSWORD",
      "scope": "openid",
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
    }

In the example below, you can see the new approach that gets an access token as well.

to configure this snippet with your account

    POST https://YOUR_DOMAIN/oauth/token
    Content-Type: application/x-www-form-urlencoded
    {
      "grant_type": "password",
      "username": "USERNAME",
      "password": "PASSWORD",
      "audience": "https://YOUR_DOMAIN/api/v2/",
      "scope": "read:current_user",
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET",
    }

In order to get an Access Token that can access the Management API:

  • Set the aud to https://YOUR_DOMAIN/api/v2/

  • Ask for the scope read:current_user

Once you have the access token you can use it to call the endpoint. This part remains the same, nothing else changes in the request except for the value you use as Bearer token. The response remains also the same.

Embedded Lock or auth0.js

If you embed either Lock v11 or auth0.js v9 in your application, then you are using cross-origin authentication. This is used to authenticate users when the requests come from different domains.

If you use auth0.js to access the Management API and manage your users, then your script will have to be updated.

In the example below, you can see the old approach.

to configure this snippet with your account

    // get an ID Token
    var webAuth = new auth0.WebAuth({
      clientID: 'YOUR_CLIENT_ID',
      domain: 'YOUR_DOMAIN',
      redirectUri: 'https://YOUR_APP/callback',
      scope: 'openid',
      responseType: 'id_token'
    });
    // create a new instance
    var auth0Manage = new auth0.Management({
      domain: 'YOUR_DOMAIN',
      token: 'ID_TOKEN'
    });

In this example, you can see the new approach.

to configure this snippet with your account

    // get an Access Token
    var webAuth = new auth0.WebAuth({
      clientID: 'YOUR_CLIENT_ID',
      domain: 'YOUR_DOMAIN',
      redirectUri: 'https://YOUR_APP/callback',
      audience: 'https://YOUR_DOMAIN/api/v2/',
      scope: 'read:current_user',
      responseType: 'token id_token'
    });
    // create a new instance
    var auth0Manage = new auth0.Management({
      domain: 'YOUR_DOMAIN',
      token: 'ACCESS_TOKEN'
    });

  • Ask for both an ID token and an access token in the response

    responseType: 'token id_token'

  • Set the Management API as the intended audience of the token

    audience: 'https://YOUR_DOMAIN/api/v2/'

  • Ask for the required permission

    scope: 'read:current_user'

  • Authenticate with the Management API using the access token

Account Linking changes

The changes in this functionality are the following:

  • You can no longer use an ID Token at the Authorization header

  • If you use an access token at the Authorization header, with update:users as the granted permission, then you can send at the request's body either the user_id or the ID Token of the secondary account

  • If you use an access token at the Authorization header, with update:current_user_metadata as the granted permission, then you can only send the ID Token of the secondary account in the request's body. The following must apply:

    • The ID token must be signed using RS256 (you can set this value at Dashboard > Applications > Application Settings > Advanced Settings > OAuth)

    • The claim aud of the ID token, must identify the application, and be the same value with the azp claim of the access token

Restrictions

The access tokens used to access the Management API must only hold one value at the aud claim. If your token contains more than one value, then your request to the Management API will error out.

Learn more