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

# リソース所有者のパスワードレス資格情報交換を移行する

> パスワードレスAPIの呼び出しと応答を/oauth/roから/oauth/tokenに移行する方法について説明します。

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

リソース所有者のパスワードのサポートが`/oauth/token`に追加されました。`/oauth/ro`エンドポイントの使用は2017年7月8日に廃止されました。`/oauth/ro`エンドポイントは、IDトークンやアクセストークンのためにエンドユーザーがメールまたはSMSで受信するワンタイムパスワード（OTP）のやり取りに使用されていました。Auth0にはこのユースケースの`/oauth/ro`に代わる新しいAPIが実装されているため、その新しいエンドポイントの使用をお勧めします。

## 影響のある機能

この変更がユーザーに影響するのは、リソース所有者のパスワードレス資格情報交換を使用していて、Auth0ライブラリーやSDKを使わずに`/oauth/ro`を直接呼び出す場合です。

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  ユーザーの`/oauth/ro`ベースのアクセストークンが期限切れになると、強制的に再認証が行われます（強制ログアウトが必要）。これは、`/oauth/ro`のリフレッシュトークンでは、`/oauth/token`を呼び出して新しいアクセストークンを取得することができないからです。`/oauth/ro`から`/oauth/token`への移行時に、ログインしているユーザーはすべてログアウトしなければなりません。
</Callout>

## アクション

### 要求の変更内容

これまで、`/oauth/ro`への要求には、以下のようなペイロードが含まれていました。

```javascript 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"
    }
```

新しい実装では以下が変更されています。

* トークン交換を実行するエンドポイントは`/oauth/token`になりました。
* Auth0独自の付与タイプは、特定の接続（またはレルム）からユーザーを認証するために使用されます。
* Auth0では、カスタムAPIで定義されたスコープの他に、標準OIDCスコープがサポートされます。
* 上記の`favorite_color`など、これらのどのカテゴリーにも該当しないスコープは、有効なスコープではなくなりました。
* `device`パラメーターは削除されています。
* `audience`パラメーターは任意です。

以下は、`/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="javascript" />

* ここでは、付与タイプに`http://auth0.com/oauth/grant-type/passwordless/otp`を指定します。
* `client_id`と`username`パラメーターに変更はありません。
* `client_secret`は、機密クライアント（通常のWebアプリなど）には指定する必要があります。
* ワンタイムパスワードは`password`パラメーターではなく、`otp`パラメーターに含めて送信する必要があります。
* `realm`は接続を識別するために使用され、以前の呼び出しからの`connection`パラメーターを置き換えます。
* `scope`パラメーターはほとんど同じですが、OIDC以外の値は受け入れません。
* `audience`パラメーターは追加して、トークンの対象であるAPIオーディエンスを示すことができます。

### 応答での変更

`/oauth/ro`からの応答は、以下のような形式になります。

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

* 返されるアクセストークンは、`/userinfo`エンドポイント（`audience`パラメーターで指定のAPIにRS256を署名アルゴリズムが使われている場合）と任意のカスタムAPI（指定されている場合）の呼び出しに使用できます。
* IDトークンは、パブリッククライアントに要求されると、RS256を使用して強制的に署名されます。
* リフレッシュトークンは、`offline_access`スコープが付与され、APIに **［Allow offline access（オンラインでのアクセスを許可する）］** が設定されている場合にのみ返されます。

以下は、`/oauth/token`から返されたOIDC準拠の応答の例です。

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

### SDK使用でのコード変更

Auth0が提供するAndroidまたはiOS用のネイティブライブラリーをアプリケーションが使用している場合には、ライブラリーのバージョンを必ず以下の最小バージョン以降にしてください。また、ライブラリーを構成する際には、必ず［`OIDC Conformant`（OIDC準拠）］フラグを`true`に設定してください。

| ライブラリー       | 最小バージョン |
| ------------ | ------- |
| Android SDK  | 1.2     |
| Lock Android | 2.17    |
| Swift SDK    | 1.20.0  |
| Lock iOS     | 2.14.0  |

### 移行を確認する

1. 廃止されたエンドポイントを使用しているか確認するには、[テナントログ](https://manage.auth0.com/#/logs)を確認し、フィルターを **［Deprecation Notice（廃止の通知）］** に設定して「`oauth/ro` **passwordless:This feature is being deprecated** （パスワードレス：この機能は廃止されました）」というログを確認します。この検索は、「`type:depnote AND description:*passwordless*`」というクエリを使って直接行うこともできます。
2. コードベースを移行し、アプリがエンドポイントを呼び出していないことを確認したら、[［Dashboard］](https://manage.auth0.com/#/tenant/advanced)>**［Tenant Settings（テナント設定）］>［Advanced（詳細）］** に移動します。
3. **［Migrations（移行）］** まで下へスクロールして、 **［Legacy** `/oauth/ro` **Endpoint（レガシー/oauth/roエンドポイント）］** をオフにします。このスイッチをオフにすると、廃止されたエンドポイントがテナントで無効となり、使用を防ぐことができます。

このスイッチをオフにしてログインできなくなった場合は、レガシーコードの全インスタンスがアプリケーションからまだ完全に削除されていません。

移行が運用環境で正常に動作している場合には、このスイッチをオフにしたままにできます。これで、廃止された機能は今後使用されることがなくなります。

## もっと詳しく

* [リソース所有者のパスワードフローを移行する](/docs/ja-jp/troubleshoot/product-lifecycle/past-migrations/migration-oauthro-oauthtoken)
