Auth0 Hooksは、Auth0 Rulesが提供するカスタマイズ機能をさらに充実させてきました。現在はAuth0 RulesとAuth0 Hooksと同様の機能を1つで実現できる、Auth0 Actionsが強力な統合環境を提供しています。この記事では既存のAuth0 HooksをAuth0 Actionsに移行する方法を説明します。
Auth0 Actionsとカスタマイズ
Okta Customer Identity Cloud (Powered by Auth0)の強みの1つは、拡張性に焦点を当てていることです。基本的なログインおよびログアウト機能に加えて、特定の要件に合致するよう、Okta Customer Identity Cloudの裏側の処理の一部を標準的なフローから変更できます。たとえば、ユーザーのアプリケーション登録時に追加の認証チェックや特定の処理を実行できます。
これまでAuth0 RulesとAuth0 Hooksを用いてこのフローのカスタマイズができました。Auth0 Rulesは認証フローのカスタマイズに利用できます。一方、Auth0 Hooksは、ユーザー登録前と登録後、パスワード変更、SMS送信時などいくつか定義されている時点の処理をカスタマイズできます。
現在ではAuth0 RulesやAuth0 Hooksとほぼ同等のカスタマイズを実現できるAuth0 Actionsを利用できます。 Auth0 Actionsは、Auth0 RulesとAuth0 Hooksで提供していた拡張ポイントをカスタマイズするための統合された開発環境を1つの機能として提供します。 Auth0 Actionsは、Auth0 RulesやAuth0 Hooksと同じ機能を提供するだけではありません。開発エクスペリエンスを向上する追加機能も提供します。
- Auth0 Actionsは統合バージョンシステムを提供します。本番環境のAuth0 Actionsに影響を与えることなくAuth0 Actionsの変更や複数のバージョンを作成できます。また、以前のバージョンの復元も可能です。
- Auth0 Actionsエディターはコードヒント、すべてのnpmパッケージ、および分離されたシークレット情報の管理をサポートします。
- Auth0マーケットプレイスで提供されているノーコードインテグレーションを利用できます。弊社パートナーが構築したインテグレーションはユーザーの同意管理、プログレッシブプロファイリング、ユーザー検証などの一般的なIDユースケースを拡張します。これらのインテグレーションを利用すると、カスタムコードを利用した場合に比べて開発コストとメンテナンスコストを削減しつつ、迅速な市場投入を可能にします。
Auth0 Actionsの紹介については、こちらの記事をお読みください。
Auth0 Actionsは改善されたカスタマイズ環境をもたらしますが、Auth0 RulesとAuth0 Hooksは提供終了日まで引き続き利用可能であり、Auth0 Actionsと共存できます。Auth0 RulesとAuth0 HooksはAuth0 Actionsの前に実行されることに注意してください。
現在、Auth0 Actionsは、Auth0 RulesとAuth0 Hooksの代替として推奨されています。この記事では、Auth0 HooksをAuth0 Actionsに移行するためのガイドラインを説明します。Auth0 RulesからAuth0 Actionsへの移行も併せてご覧ください。
コード変換ガイドライン
Auth0 Hooksを同等のAuth0 Actionsに変換するには、このセクションのガイドラインに従ってください。
Auth0 Hookの種類とAuth0 Actionのトリガーとのマッピング
最初のステップとして、Auth0 Hookの種類に対応するAuth0 Actionのトリガーを特定します。Auth0 Actionトリガーは、フロー内で発生するイベントです。次の表は、各Auth0 Hookの種類をそれぞれのAuth0 Actionトリガーにマッピングしています。
Auth0 Hookの種類 | Auth0 Actionのトリガー |
---|---|
Pre-User Registration | Pre User Registration |
Post-User Registration | Post User Registration |
Post-Change Password | Post Change Password |
Send Phone Message | Send Phone Message |
Client Credential Exchange | M2M/Client-Credentials |
Auth0 Hookの種類とAuth0 Actionのトリガーの名前は、ほぼ同じです。そのためAuth0 HooksをAuth0 Actionsに変換する場合は、適切なトリガーを選択してAuth0 Actionを作成します。トリガーは次の図に示すようにリストから選択します。
トリガーを選択すると、Auth0 Actionエディターに空の名前付きエクスポート宣言が表示されます。選択したトリガーによってエクスポートの名前が異なります。たとえば、Post-User Registration HookをPost User Registration Actionトリガーに変換するとAuth0 Actionエディターに次のコードが表示されます。
exports.onExecutePostUserRegistration = async (event) => { };
次の表ではAuth0 Hookの種類と対応するエクスポート名のマッピングを確認できます。
Auth0 Hookの種類 | Auth0 Actionのトリガー | エクスポート名 |
---|---|---|
Pre-User Registration | Pre User Registration |
|
Post-User Registration | Post User Registration |
|
Post-Change Password | Post Change Password |
|
Send Phone Message | Send Phone Message |
|
Client Credential Exchange | M2M/Client-Credentials |
|
Auth0 Hookの実装は、新しく作成したAuth0 Actionに組みこみます。ただし、いくつかの変更を加える必要があります。
パラメータのマッピング
Auth0 Hooksで使用されている関数は、Hookのタイプに応じて、ユーザー、クライアント、リクエストなどに関するコンテキストデータを複数のパラメータで受け取ります。そのため、ほとんどのHook関数には、
user
、context
、およびcb
という3つのパラメータが用意されています。一部のHookタイプの関数では、さらに別のパラメータで追加のデータを受け取ります。Auth0 Actionsは、実行環境からAction関数に渡されるデータを最大2つの引数 (
event
およびapi
) に統合します。Hookのuser
オブジェクトとcontext
オブジェクトのすべての読み取り専用プロパティは、Auth0 Actionsのevent
オブジェクトに含まれています。また、ユーザーメタデータの追加など、実行環境とのインタラクションはapi
オブジェクトのメソッドを通じて実装されています。注意すべき点として、それぞれのAuth0 Actionトリガーにおける
event
オブジェクトとapi
オブジェクトは同じ名前でありながらも、トリガーごとに構造が異なります。次の表ではAuth0 Hookの種類を起点としてそれぞれのAuth0 Actionトリガーが持つevent
オブジェクトとapi
オブジェクトのドキュメントをマッピングしています。Auth0 Hookの種類 | Auth0 Actionエクスポート名 | docs | docs |
---|---|---|---|
Pre-User Registration |
| docs | docs |
Post-User Registration |
| docs | |
Post-Change Password |
| docs | |
Send Phone Message |
| docs | |
Client Credential Exchange |
| docs | docs |
依存関係の処理
Auth0 Hooksではさまざまな機能を追加するために依存関係を含めることができます。数千のnpmパッケージを利用できますが、npm レジストリで利用可能なすべてのパッケージを利用できるわけではありませんでした。Auth0 Hooksで利用できないパッケージ(またはnpmパッケージの特定のバージョンのみ)が必要な場合は、その旨をリクエストする必要がありました。
Auth0 Actionsでは、npmレジストリ内の利用可能な100万以上にもおよぶすべてのパッケージを依存関係として追加できます。
また、Auth0 Hooksとは異なり、Auth0 Actionsではコード内でパッケージのバージョンを指定する必要はありません。たとえば、Auth0 Hooksでは次のように依存関係を宣言する必要がありました。
// ユーザー登録後の拡張ポイントAuth0 Hook module.exports = function (user, context, cb) { const axios = require("axios@0.22.0"); // ... 他のコード }
Auth0 Actionsでは、エディターのモジュールマネージャー でパッケージのバージョンを指定します。そのためコードは次のようになります。
const axios = require("axios"); exports.onExecutePostUserRegistration = async (event) => { // ... 他のコード };
ここでは依存関係を関数の本体の外側でNode.jsのスタイルでインポートしていることに注意してください。
Auth0 Hooksコールバックの変換
Client Credentials ExchangeとPre User Registrationでは、
cb
パラメーターを使用して処理の結果を返します。たとえば、コードがそのステップを完了すると、制御をランタイム環境に渡す必要があります。また、その後にランタイム環境が続けて次のAuth0 Hookを実行する可能性があります。このような場合、cb()
関数を呼び出し、処理結果または処理が失敗した場合のエラーインスタンスを渡します。Auth0 Actionsを使用すると実装がシンプルになります。制御をランタイム環境へ渡すためにコールバック関数を呼び出す必要はありません。代わりに
return
を使用します。また、Actionトリガーに渡される
api
引数を通じて、ランタイム環境と対話ができます。たとえば、M2M/Client-CredentialsおよびPre User Registration Actionトリガーは、2番目のパラメーターとしてapi
オブジェクトを持ちます。これらのActionトリガーでは、api.access.deny()
メソッドを呼び出しユーザー登録を中止できます。次のセクションでこのガイドラインの実際の適用方法について確認できます。
シークレットの変換
Auth0 Hooksと同様に、ActionエディターのAdd Secretsボタンを使用しシークレットとしてキーと値を定義できます。
Auth0 Action関数内におけるシークレットへのアクセス方法は、Auth0 Hooksでのアクセス方法と異なります。
Auth0 Hook関数では、次の例のようにシークレットにアクセスします。
module.exports = function (user, context, cb) { const mySecret = context.webtask.secrets.MY_SECRET; // ... 他のコード }
Auth0 Actionトリガー関数では、次のようにシークレットを取得します。
exports.onExecutePostChangePassword = async (event) => { const mySecret = event.secrets.MY_SECRET; // ... 他のコード };
Auth0 Actionエディターで定義されたシークレットは、
event.secrets
オブジェクトのプロパティとして利用できます。変換例
これまでのAuth0 HooksのコードをAuth0 Actionsに変換するための一般的なガイドラインをもとにいくつかの例を見てみましょう。
新しいユーザーにメタデータを追加する
次のPre User Registration Hookにおける実装を変換します。
module.exports = function (user, context, cb) { const response = {}; if (user.phoneNumber) { response.user = { user_metadata: { favorite_color: "green" } }; cb(null, response); } else { return cb(new Error("電話番号は必須項目です")); } };
このコードは、ユーザーが電話番号を提供した場合にのみ、ユーザーのメタデータにユーザーの好きな色として緑を割り当てます。電話番号を提供しない場合エラーが発生し、登録が行われません。
対応するPre User Registration Actionトリガーは次のような実装になります。
exports.onExecutePreUserRegistration = async (event, api) => { if (user.phoneNumber) { api.user.setUserMetadata("favorite_color", "green"); } else { return api.access.deny("エラー: 電話番号がありません; お気に入りの色が設定されていません", "電話番号は必須項目です"); } };
新しく作成されたメタデータをランタイム環境に戻すためには、
cb()
コールバック関数を呼び出す代わりに、api.user.setUserMetadata()
メソッドを使用します。ここでも、cb()
関数の代わりにapi
オブジェクトを使用して、ユーザーが登録できないようにします。Pre User Registrationトリガーの場合、APIオブジェクトのdeny
メソッドは内部で使用されるreason
とUIエラーを表示するために使用できるuserMessage
の2つを受け取ります。カスタムクレームの追加
Client Credentials Exchange Hookでは、次に示すように、アクセストークンにカスタムクレームを追加できます。
module.exports = function(client, scope, audience, context, cb) { const access_token = {}; const namespace = "https://myapp.example.com"; access_token.scope = scope; access_token[`${namespace}/favorite_color`] = "green"; cb(null, access_token); };
この実装を次のようにM2M/Client-Credentials Actionトリガーに変換できます。
exports.onExecuteCredentialsExchange = async (event, api) => { const namespace = "https://myapp.example.com"; api.accessToken.setCustomClaim(`${namespace}/favorite_color`, "green"); };
コールバック関数を呼び出す必要はありません。
api.accessToken.setCustomClaim()
メソッドを使用し、新しく作成したカスタムクレームに値を割り当てます。通知メールの送信
次にPost-Change Passwordについて検討します。下記のコードはSendGrid を使用し、パスワード変更時にユーザーへ電子メールを送信します。
module.exports = function (user, context, cb) { const request = require("request"); const sendgridApiKey = context.webtask.secrets.SENDGRID_API_KEY; request.post({ url: "https://api.sendgrid.com/v3/mail/send", headers: { "Authorization": "Bearer " + sendgridApiKey }, json: { personalizations: [{ to: [{ email: user.email }] }], from: { email: "admin@example.com" }, subject: "パスワードが変更されました", content: [{ type: 'text/plain', value: `${context.connection.name} アカウント ${user.email} のパスワードが最近変更されました。` }] } }, function (err, resp, body) { if (err || resp.statusCode !== 202) { return cb(err || new Error(body.errors[0].message)); } cb(); }); };
このAuth0 Hookは、Post Change Password Actionトリガーに変換できます。
exports.onExecutePostChangePassword = async (event) => { const request = require("request"); //👇 コード変更箇所 const sendgridApiKey = event.secrets.SENDGRID_API_KEY; request.post({ url: "https://api.sendgrid.com/v3/mail/send", headers: { "Authorization": "Bearer " + sendgridApiKey }, json: { personalizations: [{ to: [{ email: user.email }] }], from: { email: "admin@example.com" }, subject: "パスワードが変更されました", content: [{ type: "text/plain", //👇 コード変更箇所 value: `${event.connection.name} アカウント ${event.user.email} のパスワードが最近変更されました。` }] } }, function (err, resp, body) { if (err || resp.statusCode !== 202) { //👇 コード変更箇所 throw (err || new Error(body.errors[0].message)); } //👇 コード変更箇所 //cb(); }); };
ご覧のとおり、Hook関数からの変更はごくわずかです。変更箇所は以下の通りです。
- SendGrid APIのシークレットを取得する方法、
- connectionとユーザーデータを取得する方法、
- 実行失敗時にAuth0 Actionから抜ける方法。
また、
cb()
コールバック呼び出しに関連する最後のコメント行もご覧ください。Auth0 Actionsではこの呼び出しは不要です。移行戦略を計画する
この記事ではAuth0 HooksとAuth0 Actionsで実装するコードの主な違いを説明しました。Auth0 HooksをAuth0 Actionsへと移行する場合、コードの変換以外にも考慮すべき点が存在します。そのため本番環境において問題が発生しないような移行戦略を計画する必要があります。
この点に関しては移行後のAuth0 Actionsをテストするステージング環境を構築することをお勧めします。このステージング環境では本番環境への移行前にAuth0 Hooksから移行したAuth0 Actionsが期待どおりに実行することを確認できます。
さらに、冒頭でも言及していますが、テナント内にAuth0 HooksとAuth0 Actionsの両方を含められることを考慮してください。両方がアクティブな場合、Auth0 ActionsはAuth0 Hooksの後に実行されます。そのためそれぞれのAuth0 Actionsをアクティブにしてから移行元となるAuth0 Hooksを非アクティブにすることで、1つずつAuth0 Hooksを移行できます。いくつかまだ注意するべき点はありますが、この方法を用いると運用環境が破壊されるリスクを最小限に抑えることができます。
より詳しいAuth0 HooksからAuth0 Actionsへの移行戦略については、ドキュメントをご覧ください。
まとめ
この記事では、Auth0 Actionsが認証フローをカスタマイズするための新しい統合方法であること、さらにAuth0 Actionsを利用し、開発エクスペリエンスを強化できることを説明しました。また、この記事では既存のAuth0 Hooksを新しいAuth0 Actionsに変換するためのガイドラインについて説明し、代表的な変換例を説明しました。
Auth0 HooksからAuth0 Actionsへの移行の際は、Auth0 HooksからAuth0 Actionsへの移行プロセスの詳細ドキュメントを確認し、移行計画を事前に策定することを強くお勧めします。