Okta
オクタ
はじめに
フロントエンドからバックエンドのリソースにアクセスする際、アクセストークンを用いることで、より安全にサービス間のやり取りを実現できます。具体的な動きとして、フロントエンドは、バックエンドに対してアクセストークンと共にAPIリクエストを行います。バックエンドは、受け取ったアクセストークンの有効性を確認し、応答可否を判断します。
Auth0では、Auth0とフロントエンドをOpenID Connect(OIDC)で連携することで、フロントエンドへのアクセストークン発行に加えて、ログインユーザのロールに割り当てられた権限をアクセストークンに付与できます。これにより、ロールに応じたアクセス制御が可能となります。ユーザのロールに基づくアクセス制御を、ロールベースアクセス制御(RBAC)と呼びます。
本ブログでは、RBACの概要とRBACを用いたBackend APIのアクセス制御を実現するための設定例をご紹介します。
前提
設定例で利用するOkta社提供サンプルアプリ側の変更により、修正すべきコード内容が本ブログ記載の情報から変更となる可能性があります。
また、本ブログ記載の機能及び設定に関する内容は、2023年1月現在の情報となります。
ロールベースアクセス制御(RBAC)とは
RBACとは、システム内のユーザのロール/役割に応じてアクセス権を割り当てる方法です。同じロールを付与されたユーザは同一の権限セット、異なるロールを付与されたユーザは異なる権限セットを持ちます。
企業が持つ情報(機密文書、お客様情報等)の保護において、ユーザ毎に適切なアクセス権の付与を行い、情報に対して必要なユーザのみアクセス可能とする必要があります。この適切なアクセス権付与において、ユーザ単位ではなくロールに基づくことが重要とされています。
RBACを利用すれば、ユーザに付与されたロールに基づいてアクセス許可/拒否が決まるため、ユーザ単位での権限設定と比較して、以下のメリットがあります。
- 権限設定の簡素化による対応工数の削減
- ロール付与/変更のみでユーザの権限設定を完結
- ロールに付与された権限変更によるユーザ権限の一括変更が可能
- 権限設定ミスの回避
- 設定簡素化による意図しない権限付与発生の防止
設定例:RBACを利用したBackend APIのアクセス制御
Okta社提供サンプルアプリを活用し、RBACを利用したBackend APIのアクセス制御を実現します。本設定例では、SPAのプログラムとしてJavaScript、Backend APIはNode.js(Express)を利用します。
ユーザがAuth0へログインした際、フロントエンド(SPA)はAuth0からJSON Web Token(JWT)形式のアクセストークンを取得します。取得したアクセストークンでBackend APIにアクセスし、Backend API側でアクセストークンを検証し、許可されたリソースを返す流れとなります。
実現にあたり、必要な設定の流れは以下の通りです。
0. 事前準備
1. SPAサンプルアプリ起動
2. Backend API起動
3. Permission追加
4. ロール作成とPermission付与
5. ユーザ作成とロール付与
6. Backend APIに対する認可要求を設定
7. Backend APIリクエストボタン設置
ここから、具体的な設定方法をご紹介します。
0. 事前準備
以降の設定を行う前に、以下を準備しましょう。
- MacOSまたはWindows PC
- Node.js, Node Package Managerのインストール
- Auth0無料トライアルアカウントの発行(参考: [Auth0トライアル利用方法])
1. SPAサンプルアプリ起動
[Auth0とサンプルアプリケーションの連携設定方法]を参考に、Okta社が提供するSPAサンプルアプリ(JavaScript)を起動します。
2. Backend API起動
- Auth0管理画面で、[Applications] > [APIs]をクリック
- [+Create API]をクリック
- 各項目を設定後、[Create]をクリック
- Name:例) My API (任意の名称)
- Identifier:例) api://my-auth0-workshop-api (APIの識別子)
- 以下URLにアクセスし、Backend/APIの[Node(Express)API]をクリック
Quickstarts - Auth0 docs
- Express.js API applicationページへ遷移後、[Log in]ボタンをクリック
- ログイン後、設定対象のAuth0テナントを選択し、ページ内[①Define permissions]の[Download Sample]をクリック
- ドロップダウンリストから③で作成したAPIを選択し、[DOWNLOAD]をクリック
- ダウンロードしたファイルを任意のフォルダで解凍
- 解凍したフォルダで以下コマンドを実行し、Backend APIを起動
$ npm install $ npm start
[補足] 以下のエンドポイントを持つAPIサーバが起動します
エンドポイント | 説明 |
/api/public |
|
/api/private |
|
/api/private-scoped |
|
3. Permission追加
「2. Backend API起動」で作成したAPIのPermission(スコープ)に、“read:messages”を追加します。その後、RBAC制御を有効化します。
- Auth0管理画面で、[Applications] > [APIs]をクリック
- 「2. Backend API起動」で作成したAPIを選択後、[Permissions]タブに移動
- 各項目を設定後、[+Add]をクリック
- Permission (Scope):例) read:messages
- Description:例) read messages(任意の説明文)
- [Settings]タブでRBAC Settings:[Enable RBAC]を有効化し、画面下部の[Save]をクリック
4. ロール作成とPermission付与
ロールを作成し、「3. Permission追加」で追加したPermissionを付与します。
- [User Management] > [Roles]へ移動し、[+Create Role]をクリック
- 各項目を設定後、[Create]をクリック
- Name:例) admin (任意の名称)
- Description:例) admin (任意の説明文)
- [Permissions]タブへ移動し、[Add Permissions]をクリック
- 各項目を設定後、[Add Permissions]をクリック
- Select permissions from existing APIs:My API(「2. Backend API起動」で作成したAPI)
- Permissions:read:messagesにチェック
- Permissionsに”read:messages”が追加されたことを確認
5. ユーザ作成とロール付与
サンプルアプリへのログインユーザを作成します。その後、ユーザに対して「4. ロール作成とPermission付与」で作成したロールを付与します。
- Auth0管理画面で、[User Management] > [Users]をクリック
- [+Create User]をクリック
- 任意のEmailとPasswordでユーザを作成
- 作成したユーザの[Roles]タブで、[Assign Roles]をクリック
- 「4. ロール作成とPermission付与」で作成したロールを指定し、[Assign]をクリック
- 該当ユーザにロールが付与されたことを確認
6. Backend APIに対する認可要求を設定
サンプルアプリへログインした際、サンプルアプリからAuth0へ認可を要求するように、サンプルアプリのコードを修正します。
- サンプルアプリの「public/js/app.js」ファイルを任意のエディタで開く
- audience及びscopeをパラメータとして追加するため、以下の通りコードを修正(赤文字範囲を追加)
(略) const configureClient = async () => { const response = await fetchAuthConfig(); const config = await response.json(); auth0Client = await auth0.createAuth0Client({ domain: config.domain, clientId: config.clientId, authorizationParams: { audience: "api://my-auth0-workshop-api", scope: "profile email read:messages" } }); }; (略)
7. Backend APIリクエストボタン設置
サンプルアプリ画面上に、Backend APIを呼び出すボタンを設置します。
- サンプルアプリの「index.html」ファイルを任意のエディタで開く
- Backend APIを呼び出すボタンを配置するため、以下の通りコードを修正(赤文字範囲を追加)
<body class="h-100"> <div> <button class="btn btn-primary" id="publicApiRequestBtn" onclick="publicApiRequest()"> Public API Request </button> <button class="btn btn-primary" id="privateApiRequestBtn" onclick="privateApiRequest()"> Private API Request </button> <button class="btn btn-primary" id="privateScopedApiRequestBtn" onclick="privateScopedApiRequest()"> Private-Scoped API Request </button> </div> <div id="app" class="h-100 d-flex flex-column"> (略)
- Webブラウザでサンプルアプリ(http://localhost:3000)にアクセスし、Backend APIを呼び出すボタンの追加を確認
※この時点ではボタンは機能しません
- サンプルアプリの「public/js/app.js」ファイルを任意のエディタで開く
- ボタンクリック時にBackend APIを起動させるため、以下のコードを追加
// /api/publicへのリクエスト const publicApiRequest = async () => { const myHeaders = new Headers(); const response = await fetch("http://localhost:3010/api/public", { method: "GET" }) .then((res) => { return res.json(); }) .catch((err) => { console.log(err); }); alert(JSON.stringify(response)); }; // /api/privateへのリクエスト const privateApiRequest = async () => { const myHeaders = new Headers(); const accessToken = await auth0Client.getTokenSilently(); myHeaders.set("Authorization", "Bearer " + accessToken); const response = await fetch("http://localhost:3010/api/private", { method: "GET", headers: myHeaders }) .then((res) => { return res.json(); }) .catch((err) => { console.log(err); }); alert(JSON.stringify(response)); }; // /api/private-scopeへのリクエスト const privateScopedApiRequest = async () => { const myHeaders = new Headers(); const accessToken = await auth0Client.getTokenSilently(); myHeaders.set("Authorization", "Bearer " + accessToken); const response = await fetch("http://localhost:3010/api/private-scoped", { method: "GET", headers: myHeaders }) .then((res) => { return res.json(); }) .catch((err) => { console.log(err); }); alert(JSON.stringify(response)); };
- Webブラウザ上でサンプルアプリのページを更新し、デベロッパーツールを起動※Google Chromeの場合は[F12]キーをクリックします
- 未ログイン状態の場合、[Public API Request]ボタンクリック時に以下ダイアログが開くことを確認
「{"message":"Hello from a public endpoint! You don't need to be authenticated to see this. "}」
- [Private API Request]及び[Private-Scoped API Request]クリック時、コンソール上でエラー(Error: Login required)が表示されることを確認
Backend APIリクエスト動作確認
Permission(スコープ):”read:messages”を持つロールが付与されたユーザと、付与されていないユーザで、Backend APIの呼び出し結果が異なることを確認します。
- 「5.ユーザ作成とロール付与」で作成したユーザで、サンプルアプリへログイン
- [Private-Scoped API Request]ボタンクリック時、以下ダイアログが開くことを確認
「{"message":"Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."}」
- ログアウト操作後、Permission(スコープ):”read:messages”を持つロールを付与されていないユーザでログイン
- [Private-Scoped API Request]ボタンクリック時、以下ダイアログが開くことを確認
「{"message":"Insufficient Scope"}」※スコープ不足を示すメッセージが表示されます
おわりに
本ブログでは、ロールベースアクセス制御(RBAC)の概要と、RBACを用いたBackend APIのアクセス制御設定例をご紹介しました。
Auth0の活用により、簡単にRBACの実装が可能であることを実感いただければ幸いです。
参考
お問い合わせ・資料請求
株式会社マクニカ Okta 担当
- TEL:045-476-2010
- E-mail:okta@macnica.co.jp
平日 9:00~17:00