[Auth0] Reactアプリをローカル環境で開発する際のアクセストークンの取得について

2021.06.15

こんにちは、CX事業本部の若槻です。

Auth0のReact SDKでは、アプリケーションが認可に使用するためのアクセストークンを取得するためのgetAccessTokenSilently()というメソッドが用意されています。

使い方としては、下記のようにアプリケーションからリソースサーバーのAPIへアクセスをする際に、getAccessTokenSilently()でAuth0のAPIからアクセストークンを取得し、リソースサーバーへのAPIリクエストのヘッダーに付与することにより、リソースサーバー側でAuth0による認可に使用することができます。

getAccessTokenSilently()によるアクセストークン取得

import { useAuth0 } from '@auth0/auth0-react';

export const useGetData = () => {
  const { getAccessTokenSilently } = useAuth0();
  const getData = useCallback(async () => {
    (async () => {

      // Auth0のアクセストークンの取得
      const accessToken = await getAccessTokenSilently({
        audience: REACT_APP_AUTH0_AUTHORIZER_IDENTIFIER,
        scope: 'read:current_user',
      });

      // 認可情報としてAuth0のアクセストークンをリソースサーバーへのAPIリクエストのヘッダーに乗せている
      const response = await Axios.get(
        'path/to/api',
        {
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${accessToken}`,
          },
        },
      );

ローカルで起動したアプリケーションからアクセストークンが取得できない

さて、Reactアプリを開発する際にはlocalhostなどでローカルでアプリを起動してデバッグをしながら開発を行うことになるかと思います。しかしAuth0 SDKでアクセストークンの取得を行うアプリをlocalhostで起動するとgetAccessTokenSilently()の実行でレスポンスが返らずアプリケーションが動作しなくなる場合があります。

その際の該当ユーザーのアクセスログをAuth0管理ダッシュボードで確認すると、Failed Silent AuthおよびConsent Requiredというログが記録されています。

これはAuth0の仕様によるもので、前述のログはgetAccessTokenSilently()によるサイレント認証が同意が必要なため失敗していることを意味しています。通常のインターネットドメインから接続した場合はfirst-party applicationsとなるため同意をスキップ可能だがlocalhostとして起動して接続した場合はセキュリティのためダイアログによる同意が必要、とのことです。

First-party applications can skip the consent dialog, but only if the API they are trying to access on behalf of the user has the Allow Skipping User Consent option enabled.

Note that this option only allows verifiable first-party applications to skip consent at the moment. As localhost is never a verifiable first-party (because any malicious application may run on localhost for a user), Auth0 will always display the consent dialog for applications running on localhost regardless of whether they are marked as first-party applications.

ローカルでもアクセストークンを取得できるようにする

よって、ユーザーがダイアログによる同意ができるように、アクセストークンを取得する処理を下記のようにgetAccessTokenWithPopup()に書き換えます。

getAccessTokenWithPopup()によるアクセストークン取得

import { useAuth0 } from '@auth0/auth0-react';

export const useGetData = () => {
  const { getAccessTokenSilently } = useAuth0();
  const { getAccessTokenWithPopup } = useAuth0(); //追記
  const getData = useCallback(async () => {
    (async () => {

      // Auth0のアクセストークンの取得
      /*
      const accessToken = await getAccessTokenSilently({
        audience: REACT_APP_AUTH0_AUTHORIZER_IDENTIFIER,
        scope: 'read:current_user',
      });
      */
      const accessToken = await getAccessTokenWithPopup({
        audience: REACT_APP_AUTH0_AUTHORIZER_IDENTIFIER,
        scope: 'read:current_user',
      });

      // 認可情報としてAuth0のアクセストークンをリソースサーバーへのAPIリクエストのヘッダーに乗せている
      const response = await Axios.get(
        'path/to/api',
        {
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${accessToken}`,
          },
        },
      );

この状態でアプリケーションでgetAccessTokenWithPopup()が実行されると下記のようなAuth0の同意ダイアログがポップアップで開き、同意が要求されます。クリックして同意するとアクセストークンが取得できます。

一度同意を行った環境(ブラウザなど)/アプリケーション/ユーザーでは以降の同意は不要となるため、getAccessTokenSilently()によるアクセストークン取得の実装に戻します。(むしろ、プロダクションアプリでアクセストークンを取得するたびにユーザーに同意ダイアログを要求する実装は現実的ではないため、ここは戻すべきです。)

ちなみに同意のRevokeはAuth0の管理ダッシュボードから個別に可能です。

おわりに

Reactアプリをローカル環境で開発する際のAuth0のアクセストークンの取得についてでした。

はじめこの事象に遭遇した際はブラウザのディベロッパーツールのコンソールなどにエラーが出るわけでもなく切り分けにとても苦労しました。どなたかの参考になれば幸いです。

参考

以上