APIのステップアップ認証を構成する

ステップアップ認証を使用すると、さまざまな種類のリソースへのアクセスを許可するアプリケーションは、機密情報にアクセスしたり、特定のトランザクションを実行したりするために、より強力なメカニズムを使用してユーザーに認証を要求することができます。

たとえば、銀行アプリのユーザーは、多要素認証(MFA)を使用してIDを確認した後にのみ、口座間で送金することができます。

対象がAPIの場合、スコープ、アクセストークン、およびアクションを使用して、Auth0でステップアップ認証を実装できます。アプリケーションがAPIの保護されたリソースにアクセスする場合、アクセストークンを提供する必要があります。アクセスできるリソースは、アクセストークンに含まれる権限によって異なります。これらの権限はスコープとして定義されます。

MFAのアクセストークンを検証する

スコープの確認に加えて、APIはアクセストークンを検証して次の操作を行う必要があります。

  • トークンの署名を検証します。これは、トークンの送信者が本人であることを確認し、メッセージが途中で変更されていないことを確認するために使用されます。

  • 標準クレームを検証します。

    クレーム 説明
    exp トークンの有効期限
    iss トークンの発行者
    aud トークンの意図された受信者

シナリオ:プッシュ通知による銀行取引

次のシナリオでは、アプリケーションがユーザー名とパスワードでユーザーを認証し、口座残高を要求します。口座残高情報を取得する前に、ユーザーはGuardianプッシュファクターで認証する必要があります。

銀行APIは、口座残高の表示(スコープview:balance)または資金の振替(スコープtransfer:funds)という2つの異なるレベルの承認を受け入れることができます。アプリケーションがAPIにユーザーの残高の取得を要求する場合、アクセストークンにはview:balanceスコープが含まれている必要があります。別の口座に送金するには、アクセストークンにtransfer:fundsスコープが含まれている必要があります。

ワークフロー

  1. ユーザーは、ユーザー名とパスワードの認証を使用してアプリケーションにログインします。標準ログインにより、このユーザーはAPIと対話して残高を取得できます。つまり、ユーザーが認証した後にアプリが受け取るアクセストークンには、view:balanceスコープが含まれます。

  2. アプリケーションは、アクセストークンを資格情報として使用して、残高を取得する要求をAPIに送信します。

  3. APIはトークンを検証し、残高情報をアプリケーションに送信して、ユーザーがそれを表示できるようにします。

  4. ユーザーは、あるアカウントから別のアカウントに資金を移動したいと考えています。これは、transfer:fundsスコープを必要とする高額トランザクションと見なされます。アプリケーションは同じアクセストークンを使用してAPIに要求を送信します。

  5. APIはトークンを検証し、トークンに必要なtransfer:fundsスコープがないため、アクセスを拒否します。

  6. アプリケーションはAuth0にリダイレクトします。そこで、高額スコープが要求されたため、アクションを使用してユーザーにMFAによる認証を要求します。ユーザーがMFAで正常に認証されると、正しいスコープを含む新しいアクセストークンが生成され、応答の一部としてアプリケーションに送信されます。

  7. アプリケーションは、新しいアクセストークンを使用して別の資金振替要求を送信します。このトークンには、今回はtransfer:fundsスコープが含まれています。

  8. APIはトークンを検証し、破棄して操作を続行します。

前提条件

このシナリオでは、ダッシュボードで次の項目を構成する必要があります。

アクションを作成する

transfer:fundsスコープが要求されたときに、ユーザーにMFAによる認証を要求するアクションを作成します。[Dashbord]>[Actions(アクション)]>[Flows(フロー)]に移動し、次のコンテンツを含むアクションを作成します。

exports.onExecutePostLogin = async (event, api) => {
  const CLIENTS_WITH_MFA = ['REPLACE_WITH_YOUR_CLIENT_ID'];
  // run only for the specified clients
  if (CLIENTS_WITH_MFA.includes(event.client.client_id)) {
    // ask for MFA only if scope transfer:funds was requested
    if (event.transaction.requested_scopes.indexOf('transfer:funds') > -1)
      api.multifactor.enable('any', { allowRememberBrowser: false });
    }
  }
}

Was this helpful?

/

  • CLIENTS_WITH_MFA変数には、このアクションを適用するアプリケーションのクライアントIDが含まれます。必要ない場合は、クライアントID(および後続のif条件)を削除できます。

  • event.transaction.requested_scopesプロパティには、認証要求が要求したすべてのスコープが含まれます。値transfer:fundsが含まれている場合は、context.multifactorプロパティを適切な値に設定してMFAを要求します。この場合、プッシュを使用してMFAを要求しています。

アプリを構成

ユーザーが資金を送金するという高額取引を実行しようとしているかどうかに応じて、適切な認証要求をAPIに送信するようにアプリを構成します。2つの認証要求(MFAの有無)の唯一の違いはスコープであることに注意してください。

  • MFAあり:

    https://{yourDomain}/authorize?
    audience=https://my-banking-api&
    scope=openid%20view:balance%20transfer:funds&
    response_type=id_token%20token&
    client_id={yourClientId}&
    redirect_uri={https://yourApp/callback}&
    nonce=NONCE&
    state=OPAQUE_VALUE

    Was this helpful?

    /

  • MFAなし:

    https://{yourDomain}/authorize?
    audience=https://my-banking-api&
    scope=openid%20view:balance&
    response_type=id_token%20token&
    client_id={yourClientId}&
    redirect_uri={https://yourApp/callback}&
    nonce=NONCE&
    state=OPAQUE_VALUE

    Was this helpful?

    /

パラメーター 設定
audience APIの**Identifier(識別子)**に設定する(」API設定」を参照)。当方ではhttps://my-banking-apiに設定しています。
response_type id_token tokenに設定して、応答でIDトークンとアクセストークンを両方取得するようにします。
client_id アプリケーションのクライアントIDに設定します(「アプリケーション設定」を参照)。
redirect_uri 認証後にAuth0がリダイレクトで戻すアプリケーション内のURLに設定します(アプリケーション設定を参照)。
nonce Auth0からの応答に含まれる安全な文字列値に設定します。これはトークンリプレイ攻撃の防止に使用され、response_type=id_token tokenには必須です。
state アプリケーションにリダイレクトで戻すときにAuth0が含める不透明な値に設定します。アプリケーションはCSRF攻撃を防ぐためにこの値を使用する必要があります。

APIを構成する

受信トークンを検証し、承認された権限を確認するようにAPIを構成します。

  1. 次のAPIの2つのエンドポイントを構成します。 GET /balance: 現在の残高を取得します POST /transfer: 資金を送金します

  2. Node.jsと次の複数のモジュールを使用します。

    1. Express: Express Webアプリケーションフレームワークを追加します。

    2. jwks-rsaJWKS(JSON Web Key Set)エンドポイントからRSA署名キーを取得します。expressJwtSecretを使用すると、JWTヘッダーのkidに基づいてexpress-jwtに適切な署名キーを発行するシークレットプロバイダーを生成できます。

    3. express-jwt: Node.jsアプリケーションでJWTトークンを使用してHTTP要求を認証できます。JWTを使用した作業を容易にする、いくつかの機能が提供されています。

    4. express-jwt-authz: アクセストークンに特定のスコープが含まれているかどうかを確認します。

  3. 次の依存関係をインストールします。 npm install express express-jwt jwks-rsa express-jwt-authz --save

  4. APIエンドポイントを定義し、アクセストークンを検証するミドルウェア関数を作成し、そのミドルウェアを使用してエンドポイントを保護します。server.jsファイル内のコードは、次のサンプルスクリプトのようになります。

    // set dependencies
        const express = require('express');
        const app = express();
        const jwt = require('express-jwt');
        const jwksRsa = require('jwks-rsa');
        const jwtAuthz = require('express-jwt-authz');
    
        // Create middleware for checking the JWT
        const checkJwt = jwt({
          // Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint
          secret: jwksRsa.expressJwtSecret({
            cache: true,
            rateLimit: true,
            jwksRequestsPerMinute: 5,
            jwksUri: `https://{yourDomain}/.well-known/jwks.json`
          }),
    
          // Validate the audience and the issuer
          audience: 'https://my-banking-api', // replace with your API's audience, available at Dashboard > APIs
          issuer: 'https://{yourDomain}/',
          algorithms: [ 'RS256' ] // we are using RS256 to sign our tokens
        });
    
        // create retrieve balance endpoint
        app.get('/balance', checkJwt, jwtAuthz(['view:balance']), function (req, res) {
          // code that retrieves the user's balance and sends it back to the calling app
          res.status(201).send({message: "This is the GET /balance endpoint"});
        });
    
    
        // create transfer funds endpoint
        app.post('/transfer', checkJwt, jwtAuthz(['transfer:funds']), function (req, res) {
          // code that transfers funds from one account to another
          res.status(201).send({message: "This is the POST /transfer endpoint"});
        });
    
        // launch the API Server at localhost:8080
        app.listen(8080);
        console.log('Listening on http://localhost:8080');

    Was this helpful?

    /
    APIが要求を受信するたびに、次の処理が行われます。

    1. エンドポイントはcheckJwtミドルウェアを呼び出します。

    2. express-jwtはトークンをデコードし、要求、ヘッダー、ペイロードをjwksRsa.expressJwtSecretに渡します。

    3. jwks-rsaはJWKSエンドポイントからすべての署名キーをダウンロードし、署名キーの1つがアクセストークンのヘッダー内のkidと一致するかどうかを確認します。署名キーのいずれも受信kidと一致しない場合は、エラーがスローされます。一致する場合は、正しい署名キーをexpress-jwtに渡します。

    4. express-jwtは独自のロジックを続行して、トークンの署名、有効期限、対象ユーザー、発行者を検証します。

    5. jwtAuthzは、エンドポイントに必要なスコープがアクセストークンの一部であるかどうかを確認します。指定されたスコープがアクセストークンにない場合、要求は403エラーメッセージで拒否されます。

もっと詳しく