ルールの実行に関するベストプラクティス
各ルールは、定義された順序で呼び出されるJavaScript関数として実行されます。次のルールは、前のルールが完了するまで実行されません。さらに、ルールパイプラインは、ユーザー資格情報を含むワークフローに対してのみ実行されます。ルールパイプラインは、クライアントの資格情報フロー中には実行されません。ルールに類似する機能が必要な場合、credentials-exchange
トリガーのマシンツーマシンフローのアクションで代用することができます。
パイプラインの用語では、ルールはルールに提供されたcallback
関数が呼び出されたときに完了します。関数の呼び出しに失敗すると、パイプラインの実行は停止し、最終的にはエラーが返されます。各ルールは、callback
関数を1回だけ呼び出す必要があります。
ルールの実行はJavaScriptの非同期な性質に対応しており、Promise
オブジェクトなどのコンストラクトを使用することができます。非同期処理は、非同期操作の完了を待つ間、パイプラインを事実上一時停止することになります。Auth0サーバーレスWebtaskコンテナーには通常、約20秒の実行制限があり、その後コンテナはリサイクルできます。この制限によってコンテナーがリサイクルされると、一時停止されているかどうかに関係なく、パイプラインが途中で終了され、最終的には認証エラーが返されます(global
オブジェクトもリセットされる可能性があります)。
context.redirect
を設定すると、すべてのルールが完了した時点でリダイレクトがトリガーされます(リダイレクトは設定された時点で強制されません)。リダイレクトが発生するには、すべてのルールがWebtaskコンテナーの実行制限内で完了する必要がありますが、リダイレクト処理の一環としてかかる所要時間が、その制限を超える場合があります。/continue
エンドポイント経由でAuth0にリダイレクトする場合は、理想的には1時間以内に行うことをお勧めします。/continue
エンドポイントへのリダイレクトによっても、現在のパイプラインのコンテキストで新しいコンテナーが作成され、すべてのルールが再び実行されます。
非同期実行では、非同期操作が完了した後に(JavaScript)コールバックが実行されます。このコールバックは通常、JavaScript関数のメイン(同期)本文が完了した後のいずれかの時点で呼び出されます。ルールが非同期処理を利用している場合、(Auth0)提供のcallback
関数の呼び出しは、非同期処理が完了するまで延期され、最後に呼び出される必要があります。上述のように、(Auth0)提供のcallback
関数は1回だけ呼び出す必要があります。ルール内で関数を複数回呼び出すと、予期しない結果が得られたり、エラーが発生したりすることにつながります。
contextオブジェクト
context
オブジェクトは、ルールが実行されるコンテキストに関する情報(クライアントID、接続名、セッションID、要求のコンテキスト、プロトコルなど)を提供します。コンテキストオブジェクトを使用すると、ルールは実行の理由を判断できます。たとえば、以下のサンプルフラグメントに示すように、context.clientID
とcontext.protocol
を使用して条件付き処理を実装することで、ルールロジックが実行されるタイミングを判断できます。このサンプルでは、例外処理、npm
モジュールの使用(Promise
スタイルの処理用)、およびcallback
オブジェクトに関するベストプラクティスもいくつか紹介されています。詳細については、「カスタムデータベースのアクションスクリプト環境のベストプラクティス」をお読みください。
switch (context.protocol) {
case 'redirect-callback':
return callback(null, user, context);
break;
default: {
user.app_metadata = user.app_metadata || {};
switch(context.clientID) {
case configuration.PROFILE_CLIENT: {
user.user_metadata = user.user_metadata || {};
Promise.resolve(new
Promise(function (resolve, reject) {
switch (context.request.query.audience) {
case configuration.PROFILE_AUDIENCE: {
switch (context.connection) {
.
.
}
} break;
.
.
})
)
.then(function () {
.
.
})
.catch(function (error) {
return callback(new UnauthorizedError("unauthorized"), user, context);
});
} break;
default:
return callback(null, user, context);
break;
} break;
Was this helpful?
コンテキストバイパスロジックを使用して多要素認証チェックを行う場合は、ベストプラクティスを確認することを強くお勧めします。たとえば、MFAの使用がcontext.request.query.prompt==='none'
を前提としている場合、重大なセキュリティ上の欠陥が表面化する可能性があります。さらに、context
オブジェクトの内容はセキュリティ上重要なため、オブジェクトを外部またはサードパーティのサービスに直接渡さないでください。
リダイレクト
アプリケーションが多数あり、それを一元管理するサービスが必要な場合や、SPAを使用していて、特定の条件下でユーザーがアクセストークンを取得できないようにしたい場合、ログインフローの一部としてユーザーから情報を収集するのは実用的ではない場合があります。このような場合、情報を収集したり、ユーザーにチャレンジを提供したりするための一元的な方法が必要です。
Auth0を使用すると、ユーザーから情報を収集できる任意のURLにユーザーをリダイレクトし、その後、リダイレクトをトリガーした元の/authorize要求を完了できる/continue
エンドポイントにユーザーを戻すことができます。これは強力な機能であり、ユースケースによっては、誤って実行した場合の影響は、無害なものから、アプリケーションにセキュリティの脆弱性を残すものまでさまざまです。そのため、これを正しく実行することが重要です。
ほとんどの使用例では、リダイレクトルールは、次のようなプロファイルへの変更をユーザーに促すために使用されます。
パスワード変更の強制
メールの確認
プロファイルへの情報の追加
ルールでは、ユーザーのapp_metadata
内のフラグまたは値をチェックし、Auth0への独自の/authorize呼び出しを実行するアプリケーションにリダイレクトして、ユーザーのメタデータに変更を加え、ユーザーをAuth0にリダイレクトすることをお勧めします。これは、プロファイル変更のリダイレクトや、ユーザーのログインを制限する必要がない場合に最適です。
ルールからのリダイレクトを使用すると、context.redirectによってトリガーされる追加のユーザー操作を必要とするカスタム認証フローを実装できます。ルールからのリダイレクトは、/authorize
エンドポイントを呼び出す場合にのみ使用できます。
独自のホスト型ユーザーインターフェイスへのリダイレクトは、パイプラインが完了する前に実行され、context.clientID
コンテキストごとに1回トリガーできます。リダイレクトは、本番環境で実行される場合にのみHTTPSを使用し、一般的なセキュリティの脅威を軽減するために追加のパラメーターを最小限に抑える必要があります。Auth0が提供するstate
が、提供される唯一のパラメーターであることが望ましいです。
リダイレクトされると、独自のホスト型ユーザーインターフェイスは、ユーザー認証されたコンテキストで実行され、Auth0 SSOによって信頼性アーティファクトを取得します。これらのアーティファクト(OpenID Connect(OIDC)のIDトークンやOAuth 2.0のアクセストークンなど)を取得するには、リダイレクトをトリガーしたものではないcontext.clientID
コンテキストを使用します。これを行うには、/authorize
エンドポイントにリダイレクトします。たとえば、SPAの場合は、サイレント認証を使用します。これにより、すべてのルールが再度実行される新しいパイプラインが作成され、ルール内のcontext
オブジェクトを使用して条件付き処理を実行できます。
実行する処理が完了すると、/continue
エンドポイントを介してユーザーをAuth0にリダイレクトし(提供されたstate
を指定)、パイプラインの実行が続行されます。これにより、すべてのルールが現在のパイプライン内で再度実行され、ルール内のcontext
オブジェクトを使用して条件付き処理チェックを実行できます。
Auth0のプロファイルに保管するデータは多すぎないようにします。このデータは認証および認可の目的で使用されるものです。Auth0のメタデータと検索機能は、市場調査や高い検索・更新の頻度が必要なものを想定して設計されていません。Auth0をそのような目的で使用すると、ほぼ確実にシステムの拡張性や性能に問題が生じます。データを外部システムに保管して、Auth0にポインター(ユーザーID)を保管した方が、バックエンドシステムが必要に応じてデータを取得できます。簡単なルールとして、トークンに追加したり決定を下したりするためにルールで使用する予定のアイテムのみを保存すると良いです。
情報をフロントチャネルでやり取りすると、悪意のある行為者の攻撃対象になる領域を広げることになります。これは、ルールでアクションを実行する必要がある場合にのみ実行する必要があります(UnauthorizedError
で承認試行を拒否するなど)。
userオブジェクト
user
オブジェクトは、Auth0のユーザーアカウント(ユーザープロファイル)レコードのキャッシュされたコピーへのアクセスを提供します。このオブジェクトは、Auth0管理APIにアクセスすることなく、ユーザーに関する情報へのアクセスを提供します。このアクセスは、レート制限があり、遅延することがあります。
user
オブジェクトの内容は変更できますが(たとえば、あるルールで変更を加え、別のルールがその実行に影響を与える可能性があります)、加えられた変更は保持されません。たとえば、ユーザーに関連付けられたメタデータの更新を保持することが必要になる場合がありますが、その場合は必要に応じてauth0
オブジェクトを使用して操作を実行できます。
auth0
オブジェクトを使用してユーザーを更新すると、最終的にはAuth0 Management APIが呼び出されます。Auth0 Management APIはレート制限があり、遅延の影響を受けるため、更新を実行するタイミングと頻度については注意が必要です。
context
オブジェクトには、プライマリーユーザーのユーザーIDを参照するprimaryUser
プロパティが含まれています。このユーザーIDは通常、user
オブジェクトのルートにあるuser_id
プロパティと同じになります。プライマリーユーザーは、ルールパイプラインが完了したときにAuth0エンジンに返されるユーザーであり、user_id
はAuth0テナント内でユーザーを一意に識別するためにAuth0によって生成される一意の値です。このuser_id
は不透明な値として扱う必要があります。
プライマリーユーザーが変更される可能性があるため、primaryUser
を更新する必要がある場合があります。つまり、Auth0エンジンに返されるユーザーは、ルールパイプラインエントリのユーザーとは異なります。このような場合、ルールはprimaryUser
を更新して、新しいプライマリーユーザーIDを反映する必要があります。この変更は、パイプラインの現在のインスタンスで実行される後続のルールには影響しません。user
オブジェクトは変更されません。
アイデンティティ
user
オブジェクトには、ユーザーアカウントに関連付けられたIDへの参照も含まれます。ID
プロパティはオブジェクトの配列であり、各オブジェクトには、IDプロバイダーに知られているそれぞれのIDに関連付けられたプロパティが含まれます(たとえば、provider
名、Auth0の関連付けられたconnection
、そのIDを使用して最後に認証したときにIDプロバイダーから取得されたprofileData
など)。ユーザーアカウントをリンクすると、配列に複数のエントリが作成されます。
ID
配列内の各IDには、user_id
プロパティも含まれます。このプロパティは、IDプロバイダーに知られているユーザーのIDです。user
オブジェクトのルートにあるuser_id
プロパティには、IDプロバイダーが認識しているユーザーの識別子も含まれる場合がありますが、ベストプラクティスとしては、配列IDでuser_id
プロパティを使用することをお勧めします。ユーザーオブジェクトのルートにあるuser_id
は不透明な値として扱う必要があるため、解析しないでください。
メタデータ
user_metadata
プロパティとapp_metadata
プロパティは、ユーザーに関連付けられたメタデータの2つの異なる側面を参照します。user_metadata
プロパティとapp_metadata
プロパティはどちらも、それぞれのキャッシュされたコピーへのアクセスを提供します。
ロール、グループ、部門、ジョブコードなどのユーザーの認証関連属性は、user_metadata
ではなくapp_metadata
に保存する必要があります。これは、user_metadata
は基本的にユーザーが変更できるのに対し、app_metadata
は変更できないためです。
たとえば、ユーザーに関連付けられたメタデータの更新を保持することが必要になる場合があり、必要に応じてauth0
オブジェクトを使用してそのような操作を実行できます。いずれかのメタデータオブジェクトを更新するときは、保存する情報について慎重に検討することが重要です。メタデータのベストプラクティスに従って、メタデータを過剰に使用しないように注意してください。メタデータの過剰使用は、パイプライン内での過剰な処理によって遅延が増える可能性があります。詳細については、メタデータのフィールド名とデータタイプをご覧ください。auth0
オブジェクトを使用すると、Auth0管理APIも呼び出されます。Auth0管理APIはレート制限があり、遅延の影響を受けるため、更新を実行するタイミングと頻度については注意が必要です。
callback関数
ルールに提供されるcallback
関数は、ルールの完了を示す信号として効果的に機能します。ルールは、コールバック関数の呼び出しの直後に暗示的または(JavaScript)return
ステートメントを明示的に実行して完了する必要があり、その他の操作は実行しません。
関数の呼び出しに失敗すると、パイプラインの実行は停止し、最終的にはエラー状態が返されます。各ルールは、callback
関数を1回だけ呼び出す必要があります。1回呼び出すとパイプラインの停止は防止されますが、複数回呼び出すと、予期しない結果やエラーが発生する可能性があります。
function (user, context, callback) {
getRoles(user.user_id, (err, roles) => {
if (err) return callback(err);
context.idToken['https://example.com/roles'] = roles;
return callback(null, user, context);
});
}
Was this helpful?
上記の例からわかるように、callback
関数は最大3つのパラメーターで呼び出すことができます。最初のパラメーターは必須で、ルール操作のステータスを示します。2番目と3番目のパラメーターは任意で、パイプラインの次のルールに提供されるユーザーとコンテキストを表します。これらを指定する場合、ルールに提供されるuser
およびcontext
オブジェクトを(それぞれ)渡すことが推奨されるベストプラクティスです。
特定の状況では、user
またはcontext
オブジェクトの特定のコンテンツを変更することは許容されますが、推奨されるベストプラクティスとして、user
またはcontext
オブジェクトの新規作成されたインスタンスを渡さないようにしてください。user
またはcontext
オブジェクト以外のものを渡すと、予期しない結果が生じ、例外またはエラー状態が発生する可能性があります。
ステータスパラメーターは、null
、Error
オブジェクトのインスタンス、またはUnauthorizedError
オブジェクトのインスタンスのいずれかとして渡す必要があります。nullを指定するとパイプライン処理の継続が許可されますが、その他の値を指定するとパイプラインが終了します。UnauthorizedError
はアクセス拒否を通知し、アクセス拒否の理由に関する情報を認証操作の発信者に返すことができます。これらのパラメーターのいずれかにその他の値を渡すと、予期しない結果が生じ、例外またはエラー状態が発生する可能性があります。
認証はすでに行われているため、(認証)エラーでパイプラインが早期に終了しても、ブラウザー内の認証済みセッションには影響しません。/authorizeへの後続のリダイレクトは通常、自動ログインになります。パイプラインが早期に終了すると、トークンなどの生成が停止されます。1つのオプションは、必要に応じてアプリケーションを認証APIのログアウトエンドポイントにリダイレクトし、ブラウザー内のAuth0セッションを強制的に終了することです。
ログアウトエンドポイントへの呼び出しは中断される可能性があるため、明示的なAuth0セッションの終了は保証されません。これは,unauthorized
エラーの原因となった明示的な条件を、後続のルールパイプライン実行で再チェックする必要があり、他の条件(prompt===none
など)によってこれらの条件チェックをバイパスできないようにする必要があるため重要です。