> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

> Describes the deprecation of using ID tokens as credentials for the Management API and how to migrate your configuration to use access tokens.

# Migrate to Management API Endpoints with Access Tokens

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

Using <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+tokens">ID tokens</Tooltip> to call <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip> endpoints is being deprecated. You must use <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=access+tokens">access tokens</Tooltip>. 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 <Tooltip tip="OAuth 2.0: Authorization framework that defines authorization protocols and workflows." cta="View Glossary" href="/docs/glossary?term=OAuth+2.0">OAuth 2.0</Tooltip> 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 <Tooltip tip="Token Endpoint: Endpoint on the Authorization Server that is used to programmatically request tokens." cta="View Glossary" href="/docs/glossary?term=Token+endpoint">Token endpoint</Tooltip>.
* **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.

export const codeExample1 = `https://{yourDomain}/authorize?
      scope=openid
      &response_type=id_token
      &client_id={yourClientId}
      &redirect_uri=https://{yourApp}/callback
      &nonce={nonce}
      &state={opaqueValue}`;

<AuthCodeBlock children={codeExample1} language="http" />

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

export const codeExample2 = `https://{yourDomain}/authorize?
      audience=https://{yourDomain}/api/v2/
      &scope=read:current_user
      &response_type=token%20id_token
      &client_id={yourClientId}
      &redirect_uri=https://{yourApp}/callback
      &nonce={nonce}
      &state={opaqueValue}`;

<AuthCodeBlock children={codeExample2} language="http" />

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

* Set the `audience` to `https://{yourDomain}/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:

export const codeExample3 = `{
      "iss": "https://{yourDomain}/",
      "sub": "auth0|5a620d29a840170a9ef43672",
      "aud": "https://{yourDomain}/api/v2/",
      "iat": 1521031317,
      "exp": 1521038517,
      "azp": "{yourClientId}",
      "scope": "\${scope}"
    }`;

<AuthCodeBlock children={codeExample3} language="json" />

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).

export const codeExample4 = `POST https://{yourDomain}/oauth/token
    Content-Type: application/x-www-form-urlencoded
    {
      "grant_type": "password",
      "username": "{yourUsername}",
      "password": "{yourPassword}",
      "scope": "openid",
      "client_id": "{yourClientId}",
      "client_secret": "{yourClientSecret}",
    }`;

<AuthCodeBlock children={codeExample4} language="json" />

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

export const codeExample5 = `POST https://{yourDomain}/oauth/token
    Content-Type: application/x-www-form-urlencoded
    {
      "grant_type": "password",
      "username": "{yourUsername}",
      "password": "{yourPassword}",
      "audience": "https://{yourDomain}/api/v2/",
      "scope": "read:current_user",
      "client_id": "{yourClientId}",
      "client_secret": "{yourClientSecret}",
    }`;

<AuthCodeBlock children={codeExample5} language="json" />

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

* Set the `aud` to `https://{yourDomain}/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 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.

export const codeExample6 = `// get an ID Token
    var webAuth = new auth0.WebAuth({
      clientID: '{yourClientId}',
      domain: '{yourDomain}',
      redirectUri: 'https://{yourApp}/callback',
      scope: 'openid',
      responseType: 'id_token'
    });
    // create a new instance
    var auth0Manage = new auth0.Management({
      domain: '{yourDomain}',
      token: '{yourIdToken}'
    });`;

<AuthCodeBlock children={codeExample6} language="javascript" />

In this example, you can see the new approach.

export const codeExample7 = `// get an Access Token
    var webAuth = new auth0.WebAuth({
      clientID: '{yourClientId}',
      domain: '{yourDomain}',
      redirectUri: 'https://{yourApp}/callback',
      audience: 'https://{yourDomain}/api/v2/',
      scope: 'read:current_user',
      responseType: 'token id_token'
    });
    // create a new instance
    var auth0Manage = new auth0.Management({
      domain: '{yourDomain}',
      token: '{yourMgmtApiAccessToken}'
    });`;

<AuthCodeBlock children={codeExample7} language="javascript" />

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

  `responseType: 'token id_token'`
* Set the Management API as the intended <Tooltip tip="Audience: Unique identifier of the audience for an issued token. Named aud in a token, its value contains the ID of either an application (Client ID) for an ID Token or an API (API Identifier) for an Access Token." cta="View Glossary" href="/docs/glossary?term=audience">audience</Tooltip> 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

* [Migrate to Access Tokens for Account Linking](/docs/troubleshoot/product-lifecycle/past-migrations/link-user-accounts-with-access-tokens-migration)
