mkdir myapp && cd myapp
Keycloak は、サーバーサイド JavaScript アプリを保護するために Connect の上に構築された Node.js アダプターを提供します。その目標は、Express.js のようなフレームワークと統合できる柔軟性を持たせることでした。このアダプターは、内部で OpenID Connect プロトコルを使用しています。OpenID Connect のエンドポイントと機能に関するより一般的な情報については、OpenID Connect によるアプリケーションとサービスの保護 ガイドをご覧ください。
このライブラリは、Keycloak organization から直接ダウンロードでき、ソースは GitHub で入手できます。
Node.js アダプターを使用するには、まず Keycloak 管理コンソールでアプリケーションのクライアントを作成する必要があります。このアダプターは、public、confidential、bearer-only のアクセスタイプをサポートしています。どれを選択するかは、ユースケースのシナリオによって異なります。
クライアントが作成されたら、右上にある Action をクリックし、Download adapter config を選択します。Format には *Keycloak OIDC JSON を選択し、Download をクリックします。ダウンロードされた keycloak.json
ファイルは、プロジェクトのルートフォルダーに配置します。
Node.js がすでにインストールされていることを前提として、アプリケーション用のフォルダーを作成します。
mkdir myapp && cd myapp
npm init
コマンドを使用して、アプリケーション用の package.json
を作成します。次に、依存関係リストに Keycloak connect アダプターを追加します。
"dependencies": {
"keycloak-connect": "26.1.1"
}
Keycloak
クラスは、アプリケーションとの構成と統合の中心点を提供します。最も簡単な作成方法は、引数なしで実行することです。
プロジェクトのルートディレクトリに server.js
というファイルを作成し、次のコードを追加します。
const session = require('express-session');
const Keycloak = require('keycloak-connect');
const memoryStore = new session.MemoryStore();
const keycloak = new Keycloak({ store: memoryStore });
express-session
依存関係をインストールします。
npm install express-session
server.js
スクリプトを開始するには、package.json
の 'scripts' セクションに次のコマンドを追加します。
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js" },
これで、次のコマンドでサーバーを実行できるようになりました。
npm run start
デフォルトでは、これはアプリケーションのメイン実行可能ファイル(この場合はルートフォルダー)の横にある keycloak.json
という名前のファイルを検索し、公開鍵、レルム名、さまざまな URL などの Keycloak 固有の設定を初期化します。
その場合、Keycloak 管理コンソールにアクセスするには Keycloak デプロイメントが必要です。
これで、Keycloak 管理コンソール → clients (左側のサイドバー) → クライアントを選択 → Installation → Format Option → Keycloak OIDC JSON → Download にアクセスして keycloak.json
ファイルを取得する準備ができました。
ダウンロードしたファイルをプロジェクトのルートフォルダーに貼り付けます。
このメソッドを使用したインスタンス化では、すべての妥当なデフォルトが使用されます。代替案として、keycloak.json
ファイルではなく、構成オブジェクトを提供することも可能です。
const kcConfig = {
clientId: 'myclient',
bearerOnly: true,
serverUrl: 'https://#:8080{kc_base_path}',
realm: 'myrealm',
realmPublicKey: 'MIIBIjANB...'
};
const keycloak = new Keycloak({ store: memoryStore }, kcConfig);
アプリケーションは、次を使用することで、ユーザーを優先するアイデンティティプロバイダーにリダイレクトすることもできます。
const keycloak = new Keycloak({ store: memoryStore, idpHint: myIdP }, kcConfig);
Web セッションを使用して認証のサーバーサイド状態を管理する場合は、少なくとも store
パラメーターを指定して Keycloak(…)
を初期化し、express-session
が使用している実際のセッションストアを渡す必要があります。
const session = require('express-session');
const memoryStore = new session.MemoryStore();
// Configure session
app.use(
session({
secret: 'mySecret',
resave: false,
saveUninitialized: true,
store: memoryStore,
})
);
const keycloak = new Keycloak({ store: memoryStore });
デフォルトでは、スコープ値 openid
がクエリパラメーターとして Keycloak のログイン URL に渡されますが、追加のカスタム値を追加できます。
const keycloak = new Keycloak({ scope: 'offline_access' });
インスタンス化したら、ミドルウェアを connect 対応アプリにインストールします。
そのためには、まず Express をインストールする必要があります。
npm install express
次に、以下に示すように、プロジェクトで Express を require します。
const express = require('express');
const app = express();
そして、以下のコードを追加して、Express で Keycloak ミドルウェアを構成します。
app.use( keycloak.middleware() );
最後に、main.js
に次のコードを追加して、ポート 3000 で HTTP リクエストをリッスンするようにサーバーを設定しましょう。
app.listen(3000, function () {
console.log('App listening on port 3000');
});
アプリケーションが SSL 接続を終端するプロキシの背後で実行されている場合、Express は express behind proxies ガイドに従って構成する必要があります。正しくないプロキシ構成を使用すると、無効なリダイレクト URI が生成される可能性があります。
構成例
const app = express();
app.set( 'trust proxy', true );
app.use( keycloak.middleware() );
リソースにアクセスする前にユーザーが認証されていることを強制するには、引数なしバージョンの keycloak.protect()
を使用するだけです。
app.get( '/complain', keycloak.protect(), complaintHandler );
現在のアプリのアプリケーションロールでリソースを保護するには
app.get( '/special', keycloak.protect('special'), specialHandler );
別の アプリケーションロールでリソースを保護するには
app.get( '/extra-special', keycloak.protect('other-app:special'), extraSpecialHandler );
レルムロールでリソースを保護するには
app.get( '/admin', keycloak.protect( 'realm:admin' ), adminHandler );
リソースベースの認可を使用すると、Keycloak で定義された一連のポリシーに基づいて、リソースとその特定の方法/アクションを保護できます。これにより、アプリケーションからの認可が外部化されます。これは、リソースを保護するために使用できる keycloak.enforcer
メソッドを公開することで実現されます。
app.get('/apis/me', keycloak.enforcer('user:profile'), userProfileHandler);
keycloak-enforcer
メソッドは、response_mode
構成オプションの値に応じて、2 つのモードで動作します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), userProfileHandler);
response_mode
が token
に設定されている場合、アクセス許可は、アプリケーションに送信されたベアラートークンによって表されるサブジェクトに代わってサーバーから取得されます。この場合、新しいアクセストークンが、サーバーによって付与されたアクセス許可とともに Keycloak によって発行されます。サーバーが予期されるアクセス許可を持つトークンで応答しなかった場合、リクエストは拒否されます。このモードを使用する場合、次のようにリクエストからトークンを取得できるはずです。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), function (req, res) {
const token = req.kauth.grant.access_token.content;
const permissions = token.authorization ? token.authorization.permissions : undefined;
// show user profile
});
アプリケーションがセッションを使用しており、サーバーからの以前の決定をキャッシュし、リフレッシュトークンを自動的に処理したい場合は、このモードを優先してください。このモードは、クライアントおよびリソースサーバーとして機能するアプリケーションに特に役立ちます。
response_mode
が permissions
(デフォルトモード) に設定されている場合、サーバーは新しいアクセストークンを発行せずに、付与されたアクセス許可のリストのみを返します。新しいトークンを発行しないことに加えて、このメソッドは、次のように request
を介してサーバーによって付与されたアクセス許可を公開します。
app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'permissions'}), function (req, res) {
const permissions = req.permissions;
// show user profile
});
使用中の response_mode
に関係なく、keycloak.enforcer
メソッドは、最初にアプリケーションに送信されたベアラートークン内のアクセス許可を確認しようとします。ベアラートークンがすでに予期されるアクセス許可を持っている場合、決定を取得するためにサーバーと対話する必要はありません。これは、クライアントが保護されたリソースにアクセスする前に、予期されるアクセス許可を持つアクセストークンをサーバーから取得できる場合に特に役立ちます。これにより、インクリメンタル認可などの Keycloak Authorization Services によって提供される一部の機能を使用でき、keycloak.enforcer
がリソースへのアクセスを強制しているときにサーバーへの追加リクエストを回避できます。
デフォルトでは、ポリシーエンフォーサーは、アプリケーションに定義された client_id
(たとえば、keycloak.json
経由) を使用して、Keycloak Authorization Services をサポートする Keycloak 内のクライアントを参照します。この場合、クライアントは実際にはリソースサーバーであるため、public にすることはできません。
アプリケーションがパブリッククライアント (フロントエンド) とリソースサーバー (バックエンド) の両方として機能している場合は、次の構成を使用して、強制するポリシーを持つ Keycloak 内の別のクライアントを参照できます。
keycloak.enforcer('user:profile', {resource_server_id: 'my-apiserver'})
フロントエンドとバックエンドを表すために、Keycloak で個別のクライアントを使用することをお勧めします。
保護しているアプリケーションが Keycloak 認可サービスで有効になっており、keycloak.json
でクライアントクレデンシャルを定義している場合は、追加のクレームをサーバーにプッシュして、ポリシーで使用できるようにして意思決定を行うことができます。そのためには、プッシュするクレームを含む JSON を返す function
を予期する claims
構成オプションを定義できます。
app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], {
claims: function(request) {
return {
"http.uri": ["/protected/resource"],
"user.agent": // get user agent from request
}
}
}), function (req, res) {
// access granted
アプリケーションリソースを保護するように Keycloak を構成する方法の詳細については、認可サービスガイド を参照してください。
URL 自体の一部に基づいてリソースを保護するには (各セクションにロールが存在することを前提とします)
function protectBySection(token, request) {
return token.hasRole( request.params.section );
}
app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );
高度なログイン構成
デフォルトでは、クライアントが bearer-only でない限り、すべての未承認リクエストは Keycloak ログインページにリダイレクトされます。ただし、confidential または public クライアントは、ブラウズ可能なエンドポイントと API エンドポイントの両方をホストする場合があります。認証されていない API リクエストでリダイレクトを防ぎ、代わりに HTTP 401 を返すには、redirectToLogin 関数をオーバーライドできます。
たとえば、このオーバーライドは、URL に /api/ が含まれているかどうかを確認し、ログインリダイレクトを無効にします。
Keycloak.prototype.redirectToLogin = function(req) {
const apiReqMatcher = /\/api\//i;
return !apiReqMatcher.test(req.originalUrl || req.url);
};
デフォルトでは、ミドルウェアは /logout
への呼び出しをキャッチして、ユーザーを Keycloak 中心のログアウトワークフローに送ります。これは、middleware()
呼び出しに logout
構成パラメーターを指定することで変更できます。
app.use( keycloak.middleware( { logout: '/logoff' } ));
ユーザー起動のログアウトが呼び出されると、クエリパラメーター redirect_url
を渡すことができます。
https://example.com/logoff?redirect_url=https%3A%2F%2Fexample.com%3A3000%2Flogged%2Fout
このパラメーターは、OIDC ログアウトエンドポイントのリダイレクト URL として使用され、ユーザーは https://example.com/logged/out
にリダイレクトされます。
また、ミドルウェアは、単一のセッションまたはすべてのセッションをログアウトするための Keycloak コンソールからのコールバックをサポートしています。デフォルトでは、これらのタイプの管理コールバックは /
のルート URL を基準にして発生しますが、middleware()
呼び出しに admin
パラメーターを提供することで変更できます。
app.use( keycloak.middleware( { admin: '/callbacks' } );
Node.js アダプターの使用方法を示す完全な例は、Node.js 用 Keycloak クイックスタート にあります。