イントロスペクションと失効
概要
JWTアクセストークンは公開鍵を使用してローカルで検証できますが、一部のシナリオでは認可サーバーとの通信が必要です:
- トークンイントロスペクション(RFC 7662) — トークンが現在有効かどうかを認可サーバーに問い合わせる
- トークン失効(RFC 7009) — 認可サーバーにトークンの無効化を指示する
両方の機能は clientCredentials(コンフィデンシャルクライアント)が必要です。これは認可サーバーが呼び出し元を認証するためです。
設定
イントロスペクションまたは失効を使用するには、エンドポイントとクライアント資格情報を設定します:
import { AuthrimServer } from '@authrim/server';
const authrim = new AuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',
// Introspection endpoint introspectionEndpoint: 'https://auth.example.com/oauth/introspect',
// Revocation endpoint revocationEndpoint: 'https://auth.example.com/oauth/revoke',
// Required for both introspection and revocation clientCredentials: { clientId: 'my-resource-server', clientSecret: 'resource-server-secret', },});
await authrim.init();SDKはこれらのエンドポイントを呼び出す際、クライアント資格情報を使用してHTTP Basic認証を行います。
トークンイントロスペクション(RFC 7662)
トークンイントロスペクションでは、認可サーバーにトークンの現在の状態を問い合わせることができます。これは特に以下の場合に有用です:
- 不透明トークン — 自己完結型のJWTではなく、ローカルで検証できないトークン
- リアルタイムの有効性チェック — 失効済みまたは期限切れのトークンを即座に検出
- トークンメタデータ — JWTに含まれていないクレームの取得
introspect API
const response = await authrim.introspect(token);パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
token | string | イントロスペクトするアクセストークン |
IntrospectionResponse
interface IntrospectionResponse { active: boolean; sub?: string; scope?: string; client_id?: string; username?: string; token_type?: string; exp?: number; iat?: number; nbf?: number; aud?: string | string[]; iss?: string; jti?: string; [key: string]: unknown; // Additional claims}最も重要なフィールドは active です:
active: true— トークンは有効で現在アクティブactive: false— トークンは無効、期限切れ、失効済み、または不明
使用例
const response = await authrim.introspect(accessToken);
if (!response.active) { // Token is not valid — reject the request return res.status(401).json({ error: 'invalid_token' });}
// Token is active — use the claimsconsole.log('Subject:', response.sub);console.log('Scopes:', response.scope);console.log('Client:', response.client_id);アクティブ vs 非アクティブの処理
イントロスペクションレスポンスの active: false は複数のシナリオをカバーします:
| シナリオ | active の値 | 備考 |
|---|---|---|
| 有効なトークン | true | トークンは現在有効で使用可能 |
| 期限切れトークン | false | トークンの exp が過ぎている |
| 失効済みトークン | false | トークンは明示的に失効された |
| 不明なトークン | false | このサーバーが発行したトークンではない |
| 不正な形式のトークン | false | トークンを解析できない |
スコープチェック付きイントロスペクション
const response = await authrim.introspect(accessToken);
if (!response.active) { return res.status(401).json({ error: 'invalid_token' });}
// Check scopes manually for introspected tokensconst grantedScopes = (response.scope ?? '').split(' ');const requiredScopes = ['read:orders', 'write:orders'];
const hasAllScopes = requiredScopes.every( (scope) => grantedScopes.includes(scope));
if (!hasAllScopes) { return res.status(403).json({ error: 'insufficient_scope' });}トークン失効(RFC 7009)
トークン失効は、認可サーバーに特定のトークンの無効化を指示します。失効後、そのトークンは認可サーバーやイントロスペクションを使用するリソースサーバーでは受け入れられなくなります。
revoke API
await authrim.revoke(token, tokenTypeHint?);パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
token | string | 失効するトークン |
tokenTypeHint | string | オプションのヒント:'access_token' または 'refresh_token' |
使用例
try { await authrim.revoke(accessToken, 'access_token'); console.log('Token revoked successfully');} catch (error) { console.error('Revocation failed:', error.message);}失効のユースケース
- ログアウト — ユーザーがサインアウトする際にアクセストークンを失効
- セキュリティインシデント — 侵害されたトークンを即座に無効化
- 権限変更 — ユーザーの権限が更新された際にトークンを失効(再認証を強制)
// Example: Revoke on logoutapp.post('/api/logout', auth(), async (req, res) => { const token = req.authrim!.token.token;
// Revoke the access token at the authorization server await authrim.revoke(token, 'access_token');
res.json({ message: 'Logged out' });});ローカル検証 vs イントロスペクション
ローカルJWT検証とトークンイントロスペクションの選択は、要件によって異なります:
| 基準 | ローカル検証 | イントロスペクション |
|---|---|---|
| トークン形式 | JWTのみ | JWTまたは不透明 |
| ネットワーク呼び出し | なし(キャッシュされたJWKSを使用) | あり(毎回) |
| レイテンシ | サブミリ秒 | 10-50ms |
| 失効の検出 | 不可 | 可能 |
| リアルタイムの有効性 | 不可(exp に依存) | 可能 |
| クライアント資格情報が必要 | 不要 | 必要 |
| オフライン動作 | 可能(JWKSキャッシュ後) | 不可 |
判断ガイド
flowchart TD
A["トークン受信"] --> B{"トークン形式?"}
B -->|JWT| C{"リアルタイムの
失効チェックが必要?"}
B -->|不透明| D["イントロスペクション"]
C -->|はい| E["イントロスペクション"]
C -->|いいえ| F{"機密操作?"}
F -->|はい| G["両方を使用:
ローカル + イントロスペクション"]
F -->|いいえ| H["ローカル検証"]
ハイブリッドアプローチ
機密操作では、ローカル検証とイントロスペクションを組み合わせます:
// Fast path: Local JWT validationconst tokenResult = await authrim.validateToken(accessToken);
// For sensitive operations, also check with the authorization serverif (isSensitiveOperation(req.path)) { const introspectionResult = await authrim.introspect(accessToken); if (!introspectionResult.active) { return res.status(401).json({ error: 'invalid_token', error_description: 'Token has been revoked', }); }}これにより両方の利点を得られます:
- ほとんどのリクエストに対する高速な検証(ローカルJWT検証)
- 重要な操作に対するリアルタイムの有効性(イントロスペクション)
イントロスペクション結果のキャッシュ
高スループットAPIでは、イントロスペクション結果を短期間キャッシュできます:
const INTROSPECTION_CACHE_TTL = 30_000; // 30 seconds
async function introspectWithCache(token: string) { const cacheKey = `introspect:${hashToken(token)}`;
// Check cache first const cached = await cache.get(cacheKey); if (cached) return cached;
// Call authorization server const result = await authrim.introspect(token);
// Cache the result (short TTL) if (result.active) { await cache.set(cacheKey, result, INTROSPECTION_CACHE_TTL); }
return result;}エラータイプ
| エラー | 説明 |
|---|---|
IntrospectionError | イントロスペクションエンドポイントの呼び出しに失敗 |
RevocationError | 失効エンドポイントの呼び出しに失敗 |
ClientCredentialsError | クライアント資格情報の欠落または無効 |
NetworkError | ネットワーク接続の問題 |
次のステップ
- トークン検証 — ローカルJWT検証パイプライン
- DPoP検証 — 送信者制約付きトークンの検証
- JWKS管理 — 鍵のキャッシュとローテーション
- セキュリティに関する考慮事項 — 本番環境のセキュリティチェックリスト