> ## 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 how to migrate your Passwordless API calls and responses from /oauth/ro to /oauth/token.

# Migrate Your Resource Owner Passwordless Credentials Exchange

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>;
};

Support for <Tooltip tip="Resource Owner: Entity (such as a user or application) capable of granting access to a protected resource." cta="View Glossary" href="/docs/glossary?term=resource+owner">resource owner</Tooltip> password was added to `/oauth/token`. Usage of the `/oauth/ro` endpoint was deprecated on 08 July 2017. The `/oauth/ro` endpoint was previously used to exchange a one-time password (OTP) received by the end-user email or SMS for an <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+token">ID token</Tooltip> and an <Tooltip tip="Access Token: Authorization credential, in the form of an opaque string or JWT, used to access an API." cta="View Glossary" href="/docs/glossary?term=access+token">access token</Tooltip>. Auth0 has implemented a new API that replaces `/oauth/ro` for this use case and we recommend that you migrate to using the new endpoint.

## Features affected

This change affects you if you use the resource owner <Tooltip tip="Passwordless: Form of authentication that does not rely on a password as the first factor." cta="View Glossary" href="/docs/glossary?term=passwordless">passwordless</Tooltip> credentials exchange and call `/oauth/ro` directly without the use of any Auth0 libraries or SDKs.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  When a user's `/oauth/ro` based access token has expired, Auth0 forces them to reauthenticate (forced logout required) because the `/oauth/ro` refresh token cannot be used to call `/oauth/token` for a new access token. All currently logged in user's must log in again during an `/oauth/ro` to `/oauth/token` migration.
</Callout>

## Actions

### Request changes

Previously, the payload of a request to `/oauth/ro` looked similar to this:

```json lines theme={null}
{
  "grant_type": "password",
  "client_id": "123",
  "username": "alice",
  "password": "A3ddj3w", 
  "connection": "my-database-connection",
  "scope": "openid email favorite_color offline_access",
  "device": "my-device-name"
}
```

These are the changes for the new implementation:

* The endpoint to execute token exchanges is now `/oauth/token`.
* Auth0's own grant type is used to authenticate users from a specific connection (or realm).
* Auth0 supports the standard OIDC scopes, along with the scopes which you have defined in your custom API.
* A scope that does not fit in one of these categories, such as the above `favorite_color`, is no longer a valid scope.
* The `device` parameter is removed.
* The `audience` parameter is optional.

Here is an example of the payload of a request to `/oauth/token`:

export const codeExample = `{
  "grant_type" : "http://auth0.com/oauth/grant-type/passwordless/otp",
  "client_id": "{yourClientId}",
  "client_secret": "{yourClientSecret}", // only for web apps, native apps don’t have a client secret
  "username": "{userEmailAddress}", // or "{userPhoneNumber}"
  "otp": "CODE",
  "realm": "email", // or "sms" 
  "audience" : "{yourApiIdentifier}", // in case you need an access token for a specific API
  "scopes": "openid profile email" // whatever scopes you need
}`;

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

* The grant type is specified here as `http://auth0.com/oauth/grant-type/passwordless/otp`.
* The parameters `client_id` and `username` are unchanged.
* The `client_secret` needs to be specified for <Tooltip tip="Confidential Client: A client (application) that can hold credentials securely by using a trusted backend server. Examples include a web application with a secure backend and a machine-to-machine (M2M) application." cta="View Glossary" href="/docs/glossary?term=confidential+clients">confidential clients</Tooltip> (e.g. regular web apps).
* The one-time password needs to be sent in the `otp` parameter instead of the `password` parameter.
* The `realm` is used to identify the connection, and replaces the `connection` parameter from previous calls.
* The `scope` parameter is mostly the same, but does not accept non-OIDC values.
* The `audience` parameter can be added, indicating the API <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> the token will be intended for.

### Response changes

Responses from `/oauth/ro` were similar in format to the following:

```json lines theme={null}
{
  "access_token": "SlAV32hkKG",
  "token_type": "Bearer",
  "refresh_token": "8xLOxBtZp8",
  "expires_in": 3600,
  "id_token": "eyJ..."
}
```

* The returned access token is valid for calling the `/userinfo` endpoint (provided that the API specified by the `audience` param uses RS256 as <Tooltip tip="Signing Algorithm: Algorithm used to digitally sign tokens to ensure the token has not been tampered with." cta="View Glossary" href="/docs/glossary?term=signing+algorithm">signing algorithm</Tooltip>) and optionally the custom API if one was specified.
* The ID token will be forcibly signed using RS256 if requested by a <Tooltip tip="Public Client: Client (application) that cannot hold credentials securely. Examples include a native desktop or mobile application and a JavaScript-based client-side web application (such as a single-page app (SPA))." cta="View Glossary" href="/docs/glossary?term=public+client">public client</Tooltip>.
* A <Tooltip tip="Refresh Token: Token used to obtain a renewed Access Token without forcing users to log in again." cta="View Glossary" href="/docs/glossary?term=refresh+token">refresh token</Tooltip> will be returned only if the `offline_access` scope was granted and the API has **Allow offline access** set.

Here is an example of the OIDC conformant response from `/oauth/token`:

```json lines theme={null}
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "refresh_token": "8xLOxBtZp8",
  "expires_in": 3600,
  "id_token": "eyJ..."
}
```

### Code changes when using the SDKs

If your application uses the Auth0 native libraries for Android or iOS, be sure that the version of the library you are including is at least the minimum listed below (or higher). Also, be sure to set the `OIDC Conformant` flag to `true` when configuring the libraries.

| Library      | Minimum Version |
| ------------ | --------------- |
| Android SDK  | 1.2             |
| Lock Android | 2.17            |
| Swift SDK    | 1.20.0          |
| Lock iOS     | 2.14.0          |

### Verify migration

1. To verify whether you are using the deprecated endpoint, check the [tenant logs](https://manage.auth0.com/#/logs), filter by **Deprecation Notice** and then check for logs that say `oauth/ro` **passwordless: This feature is being deprecated**. You can also perform this search directly with the following query: `type:depnote AND description:*passwordless*`.
2. Once you have migrated your codebase and are sure that your apps are not calling the endpoint, go to the [Dashboard](https://manage.auth0.com/#/tenant/advanced) under **Tenant Settings > Advanced**.
3. Scroll down to **Migrations** and toggle off **Legacy** `/oauth/ro` **Endpoint**. Turning off this switch disables the deprecated endpoint for your tenant, preventing it from being used.

If turning this switch off results in failed logins, this is a sign that you have yet to completely remove all instances of legacy code from your applications.

Once migrations have been successfully performed in production environments, the switch can be toggled off and left off, to ensure that the deprecated features can no longer be used.

## Learn more

* [Migrate Your Resource Owner Password Flow](/docs/troubleshoot/product-lifecycle/past-migrations/migration-oauthro-oauthtoken)
