【Next.js】Auth.jsとKeycloakで実装する認証基盤 その3 ~RBAC編~
はじめに
Keycloak の RBAC を Next.js アプリケーションに実装する方法を学びます。この記事はシリーズの3回目です。
今回は、最終的に以下の画像のように、ユーザーごとにアクセスできるページをロールで制御します。そのために Terraform で Keycloak の設定を行い、Next.js でのアクセス制御の実装まで、具体的なコード例を交えて学習した内容をアウトプットします。
成果物
https://github.com/kntks/blog-code/tree/main/2025/01/nextjs-keycloak-rbac
環境
バージョン | |
---|---|
Mac | Sequoia 15.2 |
Keycloak | 26.0.7 |
Docker | 26.0.0 |
Docker Compose | v2.24.5 |
Terraform | 1.10.3 |
Node.js | v22.12.0 |
環境構築
“【Next.js】Auth.jsとKeycloakで実装する認証基盤”で使用した環境を利用します。
Keycloakの設定
Keycloakの設定はすべて Terraform で作成しました。
クライアントロール
admin
: 管理者権限editor
: 編集権限read-only
: 読み取り専用権限
グループ
Admin
Engineering
Sales
ユーザー
user1
user2
user3
ユーザー、グループ、ロールの関連付け
ユーザー | グループ | 紐づけられるクライアントロール |
---|---|---|
user1 | Admin | admin |
user2 | Engineering | editor |
user3 | Sales | read-only |
参考:
- Assigning permissions using roles and groups - Keycloak Documentation
- Client roles - Keycloak Documentation
- Keycloak – Create Realm, Client, Roles, and User - Geeks for Geeks
アクセストークンへのロール追加
Keycloak では、ユーザーが特定のクライアントロールを持っている場合、そのロール情報が自動的にアクセストークンに含まれます。
アクセストークンにロールが追加される背後には、クライアントスコープ(Client Scope) の役割があります。Keycloak では、各クライアントにはデフォルトで roles
というクライアントスコープが関連付けられています。この roles
スコープが、クライアントロールをアクセストークンに含める処理を担っています。
This scope has mappers, which are used to add the roles of the user to the access token and add audiences for clients that have at least one client role.
訳)このスコープにはマッパーがあり、アクセストークンにユーザーのロールを追加し、少なくとも1つのクライアントロールを持つクライアントのオーディエンスを追加するために使用されます。
引用:Client scopes - Keycloak Documentation
ユーザーへのロール割り当て
今回、ユーザーへ直接ロールの割り当てる代わりに、グループにロールを割り当て、ユーザーをグループに所属させる方法を採用します。
グループに所属しているユーザーは、そのグループに割り当てられたクライアントロールを自動的に持つことになります。
参考:Groups - Keycloak Documentation
Next.jsでのロールチェック実装
Auth.jsを使ってKeycloakから取得したロール情報を扱う方法を説明します。
セッションへのロール情報の追加
Keycloak からロールの情報を取得しようと考えた場合、方法が2つあります。アクセストークンから取得する方法と、ID トークンから取得する方法です。今回は ID トークンから取得する方法を実施します。
まずはじめに、Keycloak から取得できる ID トークンにはロール情報が存在しないため、ロール情報を追加する設定を行います。
ID トークンにロールの情報を入れる
Keycloak はクライアントスコープ roles
を使って、アクセストークンにロール情報を追加します。
client roles
をクリックする
Add to ID token
を On
に設定する
参考:ID token is not including roles #14617 - GitHub
ロール情報の取得とロールチェックの実装
src/auth.ts
にロール情報を取得するためのコードを追加します。
Auth.js では Keycloak から受け取った IDトークンを利用してロールを取得します。
この例では jwt コールバックで profile.resource_access を参照し、token に roles の値を渡します。
その後、session コールバックで token.roles をセッションに上書きし、session.user.roles として使用可能にします。
このとき、TypeScript で型定義を拡張すると、any 型を避けることができます。
canAccessPath
関数は、アクセス可能なパスをロールごとに設定し、そのパスにアクセスできるかどうかを判定します。
コンポーネントでのロール判定
クライアントサイドでのロールチェック
クライアントコンポーネントでロールチェックを行うには、まず SessionProvider
を作成し、アプリケーションのルートで使用する必要があります。これにより、クライアントコンポーネント内で useSession
フックを使用できるようになります。
SessionProvider
を作成し、以下のように実装します。このコンポーネントは “use client” ディレクティブを使用して、クライアントサイドでのみ実行されることを明示します。
次に、クライアントコンポーネントで useSession
フックを使用してセッション情報を取得します。セッションには先ほど追加したロール情報が含まれており、session?.user.roles
で参照できます。
実装例として、以下のようなクライアントコンポーネントを作成します。このコンポーネントは現在のユーザーのロール情報を表示します。
このように、クライアントサイドでのロールチェックは useSession
フックを使用することで簡単に実装できます。ただし、機密性の高い処理や重要な認可判定はサーバーサイドで行うことをオススメします。
サーバーコンポーネントでの実装
NextAuth
関数から取得できる auth
関数を使用することで、セッションを取得することができ、サーバーサイドでのロールチェックを行うことができます。
Protecting Resources - Auth.js
まとめ
この記事では、Next.js アプリケーションに Keycloak の RBAC を実装する方法について説明しました。
実装のポイントは以下の通りです:
-
Keycloak でのロール設定
- クライアントロールを作成し、グループ経由でユーザーに割り当て
- IDトークンにロール情報を含めるためのマッパー設定
-
Next.js での実装
- Auth.js のコールバック関数を使用したロール情報の取得
- TypeScript による型定義の拡張
- クライアント/サーバーそれぞれでのロールチェック実装
-
セキュリティ考慮事項
- パス単位のアクセス制御
- 適切なエラーハンドリングとリダイレクト