コンテンツにスキップ

イントロスペクションと失効

概要

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);

パラメータ

パラメータ説明
tokenstringイントロスペクトするアクセストークン

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 claims
console.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 tokens
const 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?);

パラメータ

パラメータ説明
tokenstring失効するトークン
tokenTypeHintstringオプションのヒント:'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 logout
app.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 validation
const tokenResult = await authrim.validateToken(accessToken);
// For sensitive operations, also check with the authorization server
if (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ネットワーク接続の問題

次のステップ