FoxAuth について
FoxAuthは、OAuth 2.0とOpenID Connect認可サーバーをMCP経由で管理する機能を提供します。アイデンティティ基盤を運用するチーム向けで、プロトコル管理はオプション機能として有効化します。
主な機能
- 01プロジェクト、チーム、クライアント、APIの管理
- 02ユーザー、グループ、IDプロバイダーの管理
- 03設定、SMTP、署名鍵の構成
- 04追記専用監査記録の確認
- 05機能フラグによるMCP管理の有効化
活用シーン
- 01OAuthクライアントとプロジェクト設定の管理
- 02エンドユーザーとグループの管理
- 03管理画面から署名鍵をローテーション
- 04有効化後にAIエージェントへ管理操作を許可
MCP 対応
MCP管理は`mcp.enabled`で制御するオプション機能です。有効にすると、同じ管理APIをAIエージェントに公開します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://auth.foxauth.dev/mcpclaude mcp add --transport http dev-foxauth-admin https://auth.foxauth.dev/mcp{"mcpServers":{"dev-foxauth-admin":{"type":"http","url":"https://auth.foxauth.dev/mcp"}}}Cursor で開く{"servers":{"dev-foxauth-admin":{"type":"http","url":"https://auth.foxauth.dev/mcp"}}}VS Code で開く{"mcpServers":{"dev-foxauth-admin":{"type":"http","url":"https://auth.foxauth.dev/mcp"}}}{"mcpServers":{"dev-foxauth-admin":{"serverUrl":"https://auth.foxauth.dev/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
https://auth.foxauth.dev/mcphttps://{foxauth_host}/mcpツール
詳細
OAuth-server.ts
Bun と TypeScript で構築された、ソースコード公開の OAuth 2.0 および OpenID Connect 認可サーバーです。
ウェブサイト · 機能 · ドキュメント · 比較 · OAuth 2.0 · OpenID Connect · Bun · FSL-1.1-ALv2 ライセンス
OAuth-server.ts は、Bun と Elysia を基盤とする TypeScript 製の、ソースコードが公開された(FSL-1.1-ALv2)、標準準拠の認可サーバーです。OAuth 2.0 と OpenID Connect を一から実装しており、ベンダーロックインなしで、ID 基盤を完全に制御できます。
機能
プロトコル機能の大半は、名前付きの機能フラグで制御されており、フラグがオフの場合、その機能のエンドポイントは一切提供されません。そのため、以下の一覧はデフォルトのインストールで利用できる機能と、意図的に有効化する機能とに分けています。この違いは、単なる編集上のものではなく、重要な意味を持ちます。
すぐに利用できる機能
- 認可コードフロー(PKCE 対応) — OAuth 2.1 に従い、パブリッククライアント、機密クライアントを問わず、すべてのクライアントで PKCE が必須です
- OpenID Connect — ID トークン、UserInfo エンドポイント、ディスカバリーを備えた OIDC Core 1.0
- 認可レスポンスの発行者識別 — すべての認可レスポンスに
issを含めます(RFC 9207) - リソースインジケーター —
resourceによるオーディエンス制限付きトークン(RFC 8707) - リフレッシュトークングラント — ローテーションと再利用検出を備えています。サポート対象の
scopesにoffline_accessが含まれている場合に提供されます。デフォルトで含まれています - RP 起点のログアウト — GET またはフォーム POST で実行でき、確認ステップを設けています
- JWT トークン — アクセストークンと ID トークンは、キーストアにあるアルゴリズムで署名されます。
bun run db:setupにより、初期の RS256 キーが作成されます。ES256 キーと EdDSA キーにも対応しています。キーはデータベースに保存され、初回実行時に生成されて/jwksで公開されます。また、独自のアドレスを持つ各プロジェクトは、それぞれのjwks_uriで独自のキーを公開します - データベースで管理するクライアント — クライアントはこのサーバー独自のストアに保存され、管理 API、動的登録、または
bun run db:setupを通じて作成されます。静的なクライアント設定ファイルはありません - 管理コンソール — プロジェクト、チーム、OAuth クライアントと API、管理者、エンドユーザーとそのグループ、上流の ID プロバイダー、SCIM プロビジョニング接続、設定、SMTP、署名キー、追記専用の監査ログを管理できます
- エンドユーザー向けセルフサービス — メールアドレスの確認とパスワードのリセットに対応し、いずれも ID ごとの試行回数とクールダウンに上限を設けています
- TOTP による第 2 要素認証 — プロジェクトごとに設定でき、管理コンソールでは任意で必須にできます(RFC 6238)
- ペアワイズサブジェクト識別子 — データベースのソルトを使った、セクターごとの
sub値 - オリジンごとのレート制限 — ルートのクラスごとに段階的に設定され、デフォルトで有効です
- サインインのブルートフォース攻撃抑制 — アドレスごとの失敗回数を永続化し、段階的にロックアウトします。抑制による拒否とパスワード間違いを区別する方法はありません
- セキュリティヘッダー — HSTS、
Permissions-Policy、フレーミングとコンテンツタイプに関する保護 - データに基づく CORS 制御 — 呼び出し元のクライアントが属するプロジェクトに登録されたオリジンのみが読み取り可能です
- プラuggable なストレージ — MongoDB、PostgreSQL、インメモリ実装を備えたアダプターアーキテクチャ
- 同意画面とログイン画面 — 認証画面と同意画面を標準で搭載しています(React + Ant Design)
- スコープベースのアクセス制御 — クライアントごとのきめ細かなスコープ適用
- 拡張可能 — アカウント検索、インタラクションポリシー、リフレッシュトークンのローテーション、リソース解決、ペアワイズ識別子、RAR 処理など、名前付きの振る舞いの拡張ポイントが 31 個あり、呼び出し時に
addons.override()で置き換えられます
オプトイン機能
実装済みですが、フラグを設定するまで無効です。コンソールの Settings または
ApplicationConfig で設定してください。コンソールで保存した変更はすぐに反映されます。
| 機能 | フラグ |
|---|---|
| クライアントクレデンシャルグラント | clientCredentials.enabled |
| JWT ベアラーグラント(ID-JAG 用、RFC 7523) | jwtBearer.enabled |
| トークン交換 — ID-JAG を発行(RFC 8693) | tokenExchange.enabled |
| DPoP — ノンスを含む、送信者に制約されたトークン(RFC 9449) | dpop.enabled |
| プッシュ型認可リクエスト(RFC 9126) | par.enabled |
| トークンイントロスペクション(RFC 7662) | introspection.enabled |
| トークン失効(RFC 7009) | revocation.enabled |
| JWT レスポンスイントロスペクション(RFC 9701) | jwtIntrospection.enabled |
| 署名付き UserInfo レスポンス | jwtUserinfo.enabled |
| 動的クライアント登録(RFC 7591) | registration.enabled |
| 登録管理(RFC 7592) | registrationManagement.enabled |
| デバイス認可グラント(RFC 8628) | deviceFlow.enabled |
| CIBA — バックチャネル認証 | ciba.enabled |
| JARM — JWT セキュア認可レスポンス | responseMode.jwt.enabled |
リクエストオブジェクト(request / request_uri) | requestObjects.enabled |
| リッチ認可リクエスト(RFC 9396) | richAuthorizationRequests.enabled |
| mTLS クライアント認証と証明書にバインドされたトークン(RFC 8705) | mTLS.enabled |
| FAPI プロファイルの動作 | fapi.enabled |
| バックチャネルログアウト | backchannelLogout.enabled |
claims リクエストパラメーター | claimsParameter.enabled |
| トークンとレスポンスの暗号化 | encryption.enabled |
| Google、Microsoft、Apple、GitHub、またはその他の OIDC プロバイダーを使用したサインイン | federation.enabled |
| MCP 経由の管理 — 同じ管理 API を AI エージェントに提供 | mcp.enabled |
| Microsoft Entra ID、Okta、または任意の SCIM クライアントから、プロジェクトのユーザーとグループを SCIM 2.0 でプロビジョニング | scim.enabled |
| Okta Universal Logout — グローバルトークン失効(個別ドラフトの期限切れが原因のため、オプトイン) | globalTokenRevocation.enabled |
| エラーストアへの記録(読み取り用インターフェースは意図的に常時提供) | errorStore.enabled |
クイックスタート
Docker Compose を使用する場合
前提条件: Compose v2 を備えた Docker。
curl -O https://raw.githubusercontent.com/RedFox-Soft/OAuth-server.ts/main/docker-compose.yml
docker compose up
これにより、MongoDB が起動し、スキーマと管理パネルがプロビジョニングされ(冪等な単発処理)、サーバーが http://localhost:3000 で稼働します。http://localhost:3000/admin を開くと、初回アクセス時に初期スーパー管理者を作成する一度限りのセットアップ画面が表示されます。ディスカバリーの URL は http://localhost:3000/.well-known/openid-configuration です。最初に docker compose up を実行する前に、docker-compose.yml の ISSUER を最終的な公開 URL に設定してください。シードされた管理クライアントのリダイレクト URI はこの値から一度だけ生成され、後から変更してもセットアップを再実行して修正されることはありません。
イメージはリリースごとに ghcr.io/redfox-soft/oauth-server-ts で公開され、バージョンと latest のタグが付けられます。アップグレードするには、再度プルして docker compose up を実行します。セットアップ処理も再実行されますが、何度実行しても安全です。
ソースから実行する場合
前提条件: Bun v1.3 以降と、稼働中の MongoDB または PostgreSQL インスタンス。
git clone https://github.com/RedFox-Soft/OAuth-server.ts.git
cd OAuth-server.ts
bun install
# Create .env — set MONGODB_URI, DATABASE_NAME, and ISSUER (see Configuration)
bun run db:setup # collections, indexes, initial RS256 signing key, admin panel seed
bun run build # bundles the console and sign-in screens into public/
bun start # http://localhost:3000
スキーマのプロビジョニング時に初期署名鍵が作成されるため、鍵の設定は不要です。サーバーが空の鍵ストアに対して起動した場合も、鍵を自動生成して保存します。
管理パネルのプロビジョニング
bun run db:setup は管理パネルもプロビジョニングします。これには予約済みの「Administrators」プロジェクトと、ファーストパーティの admin-panel OAuth クライアントが含まれます。シード処理は冪等です。既存のインストールをアップグレードした後は、bun run db:setup を再実行してください。管理クライアントとプロジェクトが作成されます。
/admin への初回アクセス時に、一度限りのセットアップ画面で最初の管理者が作成され、「Super administrators」のメンバーになります。このチームに有効なメンバーが加わると、セットアップルートは閉じられます。管理パネルを利用するには、MongoDB または PostgreSQL によるデータベース永続化が必要です(インメモリアダプターでは、再起動後にシードデータが保持されません)。
設定
| 変数 | 説明 | 例 |
|---|---|---|
MONGODB_URI | MongoDB 接続文字列 | mongodb://localhost:27017 |
DATABASE_NAME | 使用するデータベースの名前 | OAuth |
ISSUER | 認可サーバーの正規 URL | https://auth.example.com |
署名鍵
署名鍵は環境変数ではなくデータベースに保存されます。各発行者の鍵は bucketKeys 領域に保存され、インスタンス自身の鍵も含まれます。初期の RS256 署名鍵はスキーマのプロビジョニング時(bun run db:setup)に作成されます。空のストアに対してサーバーが起動した場合も、鍵を自動生成して保存します。鍵のローテーションに再起動は不要です。鍵を生成して(まず公開されます)、すべてのインスタンスがその鍵を提供するようになったら署名用に昇格させ、古い鍵を無効化します。古い鍵はその後1日間、検証に使用されます。これらの操作はコンソール、管理 API、または MCP(jwks_generate、jwks_promote、jwks_retire)から実行できます。アルゴリズムごとに署名する鍵は1つのため、RS256 と PS256 は同時に署名できます。
レート制限
リクエストは呼び出し元のオリジンごとにカウントされ、一定時間内にそのオリジンが上限を超えると 429 で拒否されます。拒否はエンドポイントの処理開始前に行われ、残り秒数を示す Retry-After が付与されます。本文は、アクセス先に応じて標準 OAuth エラー形式、管理プレーン固有の形式、または HTML ページになります。RateLimit-* ヘッダーは送信されません。これらのヘッダーがあると、しきい値を探っている呼び出し元に正確な値を知らせてしまうためです。
トークンエンドポイントを保護できるほど厳しい上限では、コンソールのアセットのバーストが拒否されてしまうため、上限は一律ではなくルートの分類ごとに設定されています:
| 分類 | 対象 | デフォルト |
|---|---|---|
strict | トークン、認可、動的登録、PAR、デバイス、CIBA、シークレットを確認するかメールを送信するすべてのエンドユーザー向け入口 | 60 / 60s |
ordinary | それ以外すべて — userinfo、イントロスペクション、失効、管理 API、MCP、その他のインタラクション画面 | 300 / 60s |
public | 静的アセット、ディスカバリーメタデータ、キーセット、すべてのクロスオリジンプリフライト | 1200 / 60s |
| exempt | GET /health のみ — ライブネスプローブが拒否されると、マシンがロードバランサーから外されます | カウントなし |
これらはすべて、管理コンソールの 設定 → レート制限、または ApplicationConfig から直接設定できます。コンソールで保存した変更は、他のサーバー設定と同様に即時反映されます。
| 設定 | デフォルト | 備考 |
|---|---|---|
rateLimit.enabled | true | インシデント時のキルスイッチ |
rateLimit.trustedProxy | true | 以下を参照 — すべての環境に適した値はありません |
rateLimit.maxTrackedOrigins | 10000 | 分類ごと。リミッター自身が使用するメモリを制限します |
rateLimit.strict.max | 60 | .windowSeconds と組み合わせて使用。デフォルトは 60 |
rateLimit.ordinary.max | 300 | .windowSeconds と組み合わせて使用。デフォルトは 60 |
rateLimit.public.max | 1200 | .windowSeconds と組み合わせて使用。デフォルトは 60 |
これらのいずれかが正の整数でない場合、サーバーは起動を拒否します。制限が適用されない状態、またはすべてのリクエストが拒否される状態で処理を続行することはありません。
rateLimit.trustedProxy は、どちらの設定にしても誤りになり得る唯一の項目です。 このサーバーの前段に何かがある場合は、有効のままにしてください(同梱の fly.toml が該当します)。無効にすると、すべての呼び出し元がプロキシ自身のアドレスとして扱われるため、インターネット全体で1つの上限を共有し、数秒以内にすべてのトラフィックが拒否されます。サーバーを直接公開している場合は、無効にしてください。有効にすると、呼び出し元はリクエストごとに新しい値を設定した Fly-Client-IP を送信でき、制限を受けなくなります。
これを使う前に知っておくべき2つの特性。 カウントはインスタンスごとにメモリ内で保持されるため、N 台のマシンが同時に処理する場合、実質的な上限は設定値の N 倍になり、インスタンスを再起動するとすべてのカウンターがクリアされます。これはリソース保護の仕組みであり、1つの送信元がサーバーにかけられる負荷を制限するものです。セキュリティ境界ではありません。絶対に守るべき制限は、ID ごとのスロットルです。確認コードの試行回数は最大5回に制限され、再送とパスワードリセットのリクエストにはクールダウンと1日あたりの上限が適用され、パスワードサインインの入口には以下のブルートフォース対策スロットルが適用されます。これらはすべて、ここでの設定とは独立して機能します。
調整。 同じアドレスの背後にある正当なサーバー間インテグレーションや、多数のユーザーが利用する企業 NAT で拒否が発生し始めた場合は、strict.max を引き上げてください。管理コンソールの読み込み中に動作が遅くなる場合は、public.max を引き上げてください。メモリが不足している場合は、maxTrackedOrigins を引き下げてください。インシデント中にすべての制限を無効にするには、rateLimit.enabled を false に設定してください。保存すると反映されます。
サインインのブルートフォース攻撃へのスロットリング
失敗したパスワード試行は、プロジェクトごと、アドレスごとにカウントされます。アドレスが上限に達すると、そのアドレスからのサインインを拒否し、ウィンドウが終了するまで、それ以降の試行をすべて拒否します。正しいパスワードを含む試行も拒否されます。その後、上限に達するたびに拒否期間は長くなり、上限に達するまで倍増します。デフォルトでは15 → 30 → 60分となり、継続的な攻撃を1日あたりおよそ120回の試行に抑えます。失敗が24時間なければ、カウンターはリセットされます。
拒否時には、通常の「ユーザー名またはパスワードが無効です」というページが表示されます。スロットリングがあること、残りの試行回数、拒否が解除される時刻は一切表示されません。いずれかを表示すると、推測対象のアドレスが実在することを攻撃者に知らせてしまうためです。同じ理由から、アカウントが存在しないアドレスについても試行をカウントします。カウンターが存在するということは、誰かがそのアドレスを入力したということだけを意味します。また、拒否はアカウントの照合前に行われるため、拒否された試行ではパスワードのハッシュ化が発生しません。したがって、1つのアドレスに対する大量のリクエストは、推測の機会だけでなくCPU負荷も抑えます。
上記の送信元ごとのリミッターとは異なり、これらのカウンターは永続化されるため、再起動後も、同時に稼働するすべてのマシン間でも上限が維持されます。これにより、これはリソース保護ではなくセキュリティ境界となります。そのため、無効にする切り替え手段は意図的に設けていません。
| 設定 | デフォルト | 備考 |
|---|---|---|
loginThrottle.failureCap | 5 | ウィンドウあたりの試行回数。最大100 |
loginThrottle.windowSeconds | 900 | 最初のロックアウト期間、および倍増の基準となる時間 |
loginThrottle.windowCeilingSeconds | 3600 | 最長ロックアウト期間。最初の期間を下回らず、24時間を超えません |
次の2つの場合は、ウィンドウの終了を待たずにカウンターが直ちにクリアされます。パスワードの検証に成功した場合と、パスワードリセットが完了した場合です。2つ目は、ロックアウトから抜け出す手段です。メールで送信された秘密情報を使用することでアドレスを管理していることが証明されますが、これはパスワードを推測する攻撃者にはできないことです。そのため、ロックアウトされたユーザーが待ち続けることはありません。リセットを_リクエスト_しただけでは、何もクリアされません。
ワンタイムコードを必須とするプロジェクトは、何度試行に失敗しても最初のウィンドウのままです。そこでパスワードを推測されてもサインインは成功しないため、ロックアウトを段階的に強化しても効果はほとんどありません。これは、予約済みのAdministratorsプロジェクトで特に重要です。運用担当者は同じサインイン画面からサインインしますが、ロックアウトから抜け出すためのセルフサービスリセットはありません。最悪の場合でも待ち時間は15分です。この画面をしっかり保護するには、二要素目を必須にしてください(Admins → 認証アプリを必須にする)。
Docker
公開済みイメージ:
docker pull ghcr.io/redfox-soft/oauth-server-ts:latest
docker run -p 3000:3000 --env-file .env ghcr.io/redfox-soft/oauth-server-ts:latest
初回起動前に、同じデータベースに対してbun run db:setupを一度実行してください(上記のComposeファイルでは自動的に実行されます)。
公開済みの各イメージには、そのダイジェストに対する署名、SBOM、ビルドの来歴を示すアテステーションが付属しています。署名には鍵を使わないため、検証時には鍵ではなく、そのイメージを作成したことが許可されているワークフローを指定します。
cosign verify \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github\.com/RedFox-Soft/OAuth-server\.ts/\.github/workflows/release\.yml@refs/tags/v' \
ghcr.io/redfox-soft/oauth-server-ts:latest
SBOM、ビルド記録、署名済みのSLSA来歴を確認する方法については、さらに3つのコマンドを参照してください。
代わりにローカルでビルドする場合:
docker build -t oauth-server-ts .
docker run -p 3000:3000 --env-file .env oauth-server-ts
エンドポイント
ほとんどのエンドポイントは機能フラグによって制御されており、フラグがオフの場合、エンドポイントはまったく提供されません。ディスカバリーでの案内が停止するだけではありません。拒否の応答は、サーバーに存在しないパスと意図的に区別できないようにしてあります。そのため、以下のリクエストが404を返す場合は、不具合を疑う前にフラグを確認してください。フラグは管理コンソールのSettingsから設定するか、ApplicationConfigに直接設定できます。コンソールで保存した変更は即座に反映されます。
常に利用可能
| エンドポイント | 説明 |
|---|---|
GET /health | 稼働状態のプローブ |
GET /.well-known/openid-configuration | OpenID Connect ディスカバリードキュメント(内容には有効な機能が反映されます) |
GET /.well-known/oauth-authorization-server | 通常の OAuth クライアント向け認可サーバーメタデータ(RFC 8414)。OpenID Connect 専用のメンバーを除いた同じドキュメントです |
GET /.well-known/security.txt | セキュリティ連絡先と情報開示ポリシー(RFC 9116) |
GET /jwks | JSON Web Key Set |
GET, POST /auth | 認可エンドポイント |
POST /token | トークンエンドポイント |
デフォルトで有効
フラグで制御されますが、無効にしない限り有効です。
| エンドポイント | 説明 | フラグ |
|---|---|---|
GET, POST /userinfo | UserInfo エンドポイント | userinfo.enabled |
GET, POST /logout | RP 起点のログアウト | rpInitiatedLogout.enabled |
POST /logout/confirm | ログアウトの確認 | rpInitiatedLogout.enabled |
オプトイン
フラグを設定するまで、デフォルトのインストールには含まれません。
| エンドポイント | 説明 | フラグ |
|---|---|---|
POST /par | プッシュ型認可リクエスト(RFC 9126) | par.enabled |
POST /token/introspect | トークンイントロスペクション(RFC 7662) | introspection.enabled |
POST /token/revocation | トークン失効(RFC 7009) | revocation.enabled |
POST /reg | 動的クライアント登録(RFC 7591) | registration.enabled |
GET /reg/:clientId | クライアント自身の登録情報の読み取り | registration.enabled |
PUT, DELETE /reg/:clientId | 登録情報の更新/削除(RFC 7592) | registrationManagement.enabled |
POST /device/auth | デバイス認可(RFC 8628) | deviceFlow.enabled |
GET, POST /device | デバイスフローのユーザーコード入力ページ | deviceFlow.enabled |
POST /backchannel | クライアント起点のバックチャネル認証(CIBA) | ciba.enabled |
POST, GET /mcp | MCP による管理 | mcp.enabled |
GET /.well-known/oauth-protected-resource/mcp | /mcp の保護されたリソースのメタデータ(RFC 9728) | mcp.enabled |
GET, POST /federation/callback | 上流の ID プロバイダーのコールバック | federation.enabled |
/scim/v2/*(ユーザー、グループ、ディスカバリー) | 各プロジェクトのアドレスでの SCIM 2.0 プロビジョニング | scim.enabled |
POST /global-token-revocation | 各プロジェクトのアドレスでの Okta Universal Logout | globalTokenRevocation.enabled |
自身の登録情報の読み取りには、registrationManagement.enabled ではなく
registration.enabled が適用されます。登録レスポンスでクライアントにその URI が渡されるため、登録が有効なときに
読み取りを拒否すると、その機能を発行した操作が使えなくなります。管理フラグが必要なのは、変更を伴うメソッドのみです。
ルートファミリー
リダイレクト、またはコンソール経由でアクセスされ、直接呼び出されることはないため、個別に列挙せずファミリーとして説明します。
| ファミリー | エントリーポイント | 説明 |
|---|---|---|
| エンドユーザー向け操作画面 | /ui/:uid/… | ログイン、同意、登録、TOTP チャレンジと登録、パスワードを忘れた場合の手続き、フローの再開。フェデレーションの各エンドポイント(/ui/:uid/federation/…)には federation.enabled が必要です |
| メールアドレスの確認 | /verify-email | 確認、コード入力、再送 |
| パスワードのリセット | /reset-password | セルフサービスによるリセット |
| 管理コンソール+API | /admin, /admin/api | プロジェクト、チーム、クライアント、管理者、エンドユーザー、フェデレーションプロバイダー、設定、SMTP、署名鍵、監査証跡、エラーストア |
| 静的アセット | /public/… | コンソールのアセット |
操作画面とセルフサービスの各ファミリーは、設計上、常に利用可能です。アカウントにロックアウトされたユーザーに、機能の切り替えを待つよう求めることはできません。/mcp はゲートされていますが、コンソールも常に利用可能です。MCP をオフにしても、コンソールまで利用できなくなってはなりません。
管理
このサーバー自体を管理します。GET /admin は、プロジェクト、チーム、OAuth クライアント、管理者、エンドユーザー、上流の ID プロバイダー、設定、署名鍵、および追記専用の監査証跡を管理するコンソールです。管理者は、このサーバー自身の発行者に対する OpenID Connect フローを通じてサインインするため、別のパスワードストアはありません。
同じ管理 API を、サーバーの OAuth 2.1 保護対象リソースとして、Model Context Protocol 経由で AI エージェントから利用できます。これはデフォルトでは無効です。この機能を使うと、エージェントには認可した管理者の権限が与えられるため、デプロイ時には意図的に有効にしてください。
- コンソールで Settings → Administration → Enable the administrative MCP control plane を選択します(保存時に適用されます)。
- MCP クライアントの接続先を
https://your-server/mcpに設定し、クライアント ID をadmin-mcp、リソースをhttps://your-server/mcpにします。
エージェントはサインインした管理者として、そのアカウントとまったく同じ権限で動作します。エージェントによる変更はすべて、コンソールと同じルート、同じチェック、同じ監査証跡を通じて実行され、各監査エントリにはオペレーターとエージェントの両方が記録されます。
意図的に実行できない操作もあります。プロジェクトまたはチームの削除、障害ストアの消去、インスタンスの管理を許可するクライアント ID の変更です。削除すると、後から調査できるものが何も残らないコンテナが破棄されます。また、最後の操作は権限昇格につながるため、これらの操作はコンソールからのみ実行できます。 その他の破壊的な操作は、2 段階で実行します。エージェントが変更内容を提示し、その特定の操作をユーザーが確認します。
ここで使用できるクライアント ID。 上記の予約済み
client_idは常に使用でき、トグル以外の設定は不要です。client_idを指定できないエージェントホストも、このサーフェスを利用できます。ただし、OAuth Client ID Metadata Document(エージェントを説明するドキュメントを指す HTTPS URL)を使って自身を識別し、スーパー管理者がコンソールの Agent access でその ID を登録している必要があります。Dynamic Client Registration を通じて自身を登録したクライアントは、どのような設定でもインスタンスを管理できません。そのクライアント ID は、要求したユーザーによってその場で生成されるため、オペレーターが許可リストに登録しても意味がないからです。
独自の MCP サーバーを保護する
同じプロトコルサーフェスは、このサーバー以外の MCP サーバーにも対応しています。プロジェクトの保護対象リソースとして、その正規 URI、認識するスコープ、トークンの検証方法を宣言します。すると、このサーバーはコードを変更したり再起動したりせずに、そのリソースだけを対象とするトークンを発行します。エージェントホストはそのリソースを検出し、エンドユーザーをサインインさせ、発行者のメタデータに記載された jwks_uri を使って MCP サーバーが検証できるトークンを持って戻ります。追加の問い合わせはありません。
OAuth で MCP サーバーを保護するでは、正しい拒否応答の例を含め、最初から最後まで説明しています。これにより、「保護されている」状態と「まだ到達していない」状態を見分けられます。
実装されている標準
Flag 列には、機能を制御するフラグを記載しています。— は常に有効であることを意味します。デフォルト設定については
Features を参照してください。
| 仕様 | 説明 | フラグ |
|---|---|---|
| OAuth 2.1 | 対象とするプロファイル:すべてのクライアントで PKCE を使用し、リダイレクト URI を厳密に照合し、リフレッシュトークンをローテーションし、Implicit と ROPC は使用しません | — |
| RFC 6749 | OAuth 2.0 認可フレームワーク | — |
| RFC 7636 | PKCE | — |
| RFC 7519 | JSON Web Token(JWT) | — |
| RFC 7517 | JSON Web Key(JWK) | — |
| RFC 9068 | OAuth 2.0 アクセストークン向け JWT プロファイル | — |
| OIDC Core 1.0 | OpenID Connect Core | — |
| OIDC Discovery 1.0 | OpenID Connect Discovery | — |
| OIDC RP-Initiated Logout 1.0 | クライアントがサインアウトを開始し、ユーザーを元の場所に戻します | rpInitiatedLogout.enabled |
| OIDC Back-Channel Logout 1.0 | サーバー間でクライアントにサインアウトを通知し、上流プロバイダーからのサインアウト通知を受信します | backchannelLogout.enabled, federation.enabled |
| RFC 8414 | OAuth 2.0 認可サーバーメタデータ | — |
| RFC 9207 | 認可サーバー発行者の識別 | — |
| RFC 8707 | リソースインジケーター | resourceIndicators.enabled |
| RFC 7009 | OAuth 2.0 トークン失効 | revocation.enabled |
| RFC 7662 | OAuth 2.0 トークンイントロスペクション | introspection.enabled |
| RFC 9701 | OAuth トークンイントロスペクション向け JWT レスポンス | jwtIntrospection.enabled |
| RFC 9126 | プッシュ型認可リクエスト(PAR) | par.enabled |
| RFC 9449 | nonce を含む DPoP | dpop.enabled |
| RFC 7591 | 動的クライアント登録 | registration.enabled |
| RFC 7592 | 動的クライアント登録管理 | registrationManagement.enabled |
| RFC 8628 | デバイス認可グラント | deviceFlow.enabled |
| RFC 7523 | JWT ベアラー認可グラント。draft-ietf-oauth-rfc7523bis に改訂案が記載されており、jwt-dpop にも対応します | jwtBearer.enabled |
| RFC 8693 | ID-JAG プロファイルとしてのトークン交換 | tokenExchange.enabled |
| ID-JAG | Identity Assertion JWT Authorization Grant(-04)。両方のロールに対応:MCP の企業管理認可 | jwtBearer.enabled, tokenExchange.enabled |
| RFC 8705 | mTLS クライアント認証と証明書バインドトークン | mTLS.enabled |
| RFC 9396 | 詳細な認可リクエスト | richAuthorizationRequests.enabled |
| RFC 9728 | OAuth 2.0 保護リソースメタデータ | mcp.enabled |
| RFC 7643 | SCIM コアスキーマ | scim.enabled |
| RFC 7644 | SCIM プロトコル | scim.enabled |
| CIBA | クライアント起点のバックチャネル認証 | ciba.enabled |
| JARM | JWT セキュア認可レスポンスモード | responseMode.jwt.enabled |
| RFC 6238 | TOTP による第 2 要素認証 | — |
| Client ID Metadata Document | クライアントを、クライアントがホストするドキュメントの URL で識別します | clientIdMetadataDocument.enabled |
セキュリティ
脆弱性は [email protected] または 非公開の脆弱性報告から報告してください。 SECURITY.mdには、対象範囲、対応時間、安全港について記載されています。
同じファイルには、コードを支える取り組みも記載されています。公開済みの 脅威モデル、CodeQL、すべてのプッシュ時および毎週の依存関係とコンテナーの スキャン(実行内容と結果の確認方法)、 SBOM とビルドの来歴情報を含む署名済みイメージ、 そして OpenSSF Scorecardです。 また、外部監査、有償のバグ報奨金制度、OpenID Foundation の認定がまだないことも記載されています。良い知らせだけを並べたセキュリティページは、信頼できるものではないからです。
コントリビューション
質問やアイデアは GitHub Discussionsへどうぞ。「使い方」などの質問は Q&A、提案は Ideas で受け付けています。
コントリビューションを歓迎します。issue またはプルリクエストを作成してください。大きな変更の場合は、まず issue を作成して提案について話し合ってください。
ライセンス
OAuth-server.ts は Functional Source License, Version 1.1, ALv2 Future
License(FSL-1.1-ALv2)の下でライセンスされています。これは Sentry が使用しているものと同じライセンスです。簡単に言うと、競合するホステッドサービスとして他者に提供する場合を除き、あらゆる目的で使用、変更、セルフホスト、再配布できます。また、各バージョンはリリースから 2 年後に Apache License 2.0 に切り替わります。
このプロジェクトは 2025 年 4 月に、Filip Skokan による node-oidc-provider のフォークとして始まりました。元のプロジェクトは MIT License の下で配布されています。その著作権表示は NOTICEに保持されています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。