トークン検証
トークン検証は@authrim/serverの中核機能です。validateToken()メソッドは、JWTの解析、署名鍵の取得、署名の検証、すべての標準クレームのチェックという完全な検証パイプラインを実行します。
validateToken API
Section titled “validateToken API”const result = await authrim.validateToken(token);| パラメータ | 型 | 説明 |
|---|---|---|
token | string | 生のJWTアクセストークン(Bearerプレフィックスなし) |
追加の検証ルールは、サーバーインスタンス作成時の tokenValidation に設定します。 |
TokenValidationOptions
Section titled “TokenValidationOptions”interface TokenValidationOptions { clockToleranceSeconds?: number; requiredScopes?: string[]; validateDPoP?: boolean; tenantClaim?: string; requireTenantClaim?: boolean; requiredTenantId?: string; allowedTenantIds?: string[]; tenantPredicate?: ( tenantId: string, claims: AccessTokenClaims, ) => boolean | Promise<boolean>;}| オプション | 型 | 説明 |
|---|---|---|
clockToleranceSeconds | number | 標準クレーム検証のクロックスキュー許容値 |
requiredScopes | string[] | トークンのscopeクレームに存在する必要があるスコープ |
validateDPoP | boolean | ミドルウェア統合で使うDPoP bound token検証ポリシー用の予約フィールド |
tenantClaim | string | tenant idを格納するクレーム名。デフォルトは tenant_id |
requireTenantClaim | boolean | tenantクレームを含まないトークンを拒否 |
requiredTenantId | string | トークンtenantがこのtenant idと完全一致することを要求 |
allowedTenantIds | string[] | トークンtenantがこのリストのいずれかであることを要求 |
tenantPredicate | (tenantId, claims) => boolean | Promise<boolean> | 高度なABAC/ReBAC向けのカスタムtenant判定 |
戻り値: TokenValidationResult
Section titled “戻り値: TokenValidationResult”validateToken() は判別可能なresult objectを返します。通常の検証失敗ではthrowしません。
type TokenValidationResult = | { data: ValidatedToken; error: null } | { data: null; error: { code: string; message: string } };検証に成功した場合、data に検証済みトークンが入ります。
interface ValidatedToken { claims: AccessTokenClaims; token: string; issuer: string; tenantId?: string; tokenType: 'Bearer' | 'DPoP'; expiresIn?: number;}| フィールド | 型 | 説明 |
|---|---|---|
claims | AccessTokenClaims | 解析・検証済みのJWTクレーム |
token | string | 元のトークン文字列 |
issuer | string | 検証済みissuer |
tenantId | string | undefined | tenantクレームがある場合の検証済みtenant id |
tokenType | 'Bearer' | 'DPoP' | クレームに基づいて検出されたトークンタイプ |
expiresIn | number | undefined | トークンの有効期限までの秒数(expから計算) |
AccessTokenClaims
Section titled “AccessTokenClaims”interface AccessTokenClaims { iss: string; sub: string; aud: string | string[]; exp: number; iat: number; nbf?: number; jti?: string; scope?: string; client_id?: string; cnf?: { jkt?: string }; [key: string]: unknown; // Custom claims}検証パイプライン
Section titled “検証パイプライン”SDKは以下のパイプラインでトークンを検証します。トークンが受け入れられるには、各ステップをパスする必要があります。
flowchart TD
A["JWT文字列を受信"] --> B["サイズチェック<br>(最大 8 KB)"]
B --> C["JWTを解析<br>(Header + Payload + Signature)"]
C --> D["アルゴリズムチェック<br>(alg: none を拒否)"]
D --> E["署名鍵を取得<br>(JWKS by kid)"]
E --> F["署名を検証<br>(RS/PS/ES/EdDSA)"]
F --> G["issを検証<br>(タイミングセーフ)"]
G --> H["audを検証<br>(タイミングセーフ)"]
H --> I["expを検証<br>(+ クロック許容値)"]
I --> J["nbfを検証<br>(+ クロック許容値)"]
J --> K["iatを検証<br>(未来でないこと)"]
K --> L["必要なスコープをチェック"]
L --> M["tenant policyをチェック"]
M --> N["トークンタイプを検出<br>(Bearer vs DPoP)"]
N --> O["TokenValidationResultを返却"]
いずれかのステップが失敗した場合、SDKは { data: null, error } を返します。以下のエラータイプセクションを参照してください。
scopeとtenantの検証は、サーバー作成時に設定します。
const authrim = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com', tokenValidation: { requiredScopes: ['orders:read'], requireTenantClaim: true, allowedTenantIds: ['tenant_a', 'tenant_b'], },});サポートされるアルゴリズム
Section titled “サポートされるアルゴリズム”SDKは署名検証に以下のJWSアルゴリズムをサポートしています:
| アルゴリズム | 鍵タイプ | 曲線 / サイズ | 説明 |
|---|---|---|---|
| RS256 | RSA | 2048+ビット | RSASSA-PKCS1-v1_5 with SHA-256 |
| RS384 | RSA | 2048+ビット | RSASSA-PKCS1-v1_5 with SHA-384 |
| RS512 | RSA | 2048+ビット | RSASSA-PKCS1-v1_5 with SHA-512 |
| PS256 | RSA | 2048+ビット | RSASSA-PSS with SHA-256 |
| PS384 | RSA | 2048+ビット | RSASSA-PSS with SHA-384 |
| PS512 | RSA | 2048+ビット | RSASSA-PSS with SHA-512 |
| ES256 | EC | P-256 | ECDSA with SHA-256 |
| ES384 | EC | P-384 | ECDSA with SHA-384 |
| ES512 | EC | P-521 | ECDSA with SHA-512 |
| EdDSA | OKP | Ed25519 | Edwards-curve Digital Signature |
クレーム検証の詳細
Section titled “クレーム検証の詳細”発行者(iss)
Section titled “発行者(iss)”issクレームは、設定されたissuer値のいずれかと正確に一致する必要があります。比較にはサイドチャネル攻撃を防止するためにタイミングセーフアルゴリズムが使用されます。
// Single issuerconst authrim = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
// Multiple issuersconst authrim = createAuthrimServer({ issuer: [ 'https://auth.example.com', 'https://auth.partner.com', ], audience: 'https://api.example.com',});オーディエンス(aud)
Section titled “オーディエンス(aud)”audクレームには、設定されたaudience値の少なくとも1つが含まれている必要があります。audクレームは単一の文字列または文字列の配列です。すべての比較はタイミングセーフです。
// Token with aud: "https://api.example.com" — matches// Token with aud: ["https://api.example.com", "other"] — matches// Token with aud: "https://other.example.com" — rejected有効期限(exp)
Section titled “有効期限(exp)”expクレームは、現在時刻にclockToleranceSecondsを加えた値と照合されます:
token is valid if: exp + clockToleranceSeconds > nowデフォルトの許容値60秒では、最大60秒前に期限切れになったトークンでも受け入れられます。
有効開始時刻(nbf)
Section titled “有効開始時刻(nbf)”存在する場合、nbfクレームは現在時刻からclockToleranceSecondsを引いた値と照合されます:
token is valid if: nbf - clockToleranceSeconds <= now発行時刻(iat)
Section titled “発行時刻(iat)”iatクレームは、トークンが未来に発行されていないことをサニティチェックします(クロック許容値を考慮):
token is valid if: iat - clockToleranceSeconds <= nowスコープ検証
Section titled “スコープ検証”requiredScopesオプションを使用して必要なスコープを適用します:
// Require specific scopesconst authrim = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com', tokenValidation: { requiredScopes: ['read:users', 'write:users'], },});SDKは、指定されたすべてのスコープがトークンのscopeクレーム(スペース区切り文字列)に存在するかをチェックします。必要なスコープが1つでも欠けている場合、validateToken() は insufficient_scope のエラーコードを返します。
BearerとDPoPの自動検出
Section titled “BearerとDPoPの自動検出”SDKはcnf(confirmation)クレームに基づいてトークンタイプを自動検出します:
- トークンに
cnf.jkt(JWK Thumbprint)が含まれている場合、トークンはDPoPとして分類されます - それ以外の場合、トークンは
Bearerとして分類されます
const result = await authrim.validateToken(token);
if (result.error) { throw new Error(result.error.message);}
if (result.data.tokenType === 'DPoP') { // This token is sender-constrained — validate the DPoP proof too await authrim.validateDPoP(dpopProof, { method: 'GET', uri: 'https://api.example.com/resource', accessToken: token, expectedThumbprint: result.data.claims.cnf!.jkt!, });}完全なDPoP検証については、DPoP検証を参照してください。
基本的なトークン検証
Section titled “基本的なトークン検証”import { createAuthrimServer } from '@authrim/server';
const authrim = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});await authrim.init();
try { const result = await authrim.validateToken(accessToken); if (result.error) { throw new Error(result.error.message); }
console.log('User:', result.data.claims.sub); console.log('Scopes:', result.data.claims.scope); console.log('Expires in:', result.data.expiresIn, 'seconds');} catch (error) { console.error('Token validation failed:', error.message);}必要なスコープ付き
Section titled “必要なスコープ付き”const authrim = createAuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com', tokenValidation: { requiredScopes: ['read:orders', 'write:orders'], },});
const result = await authrim.validateToken(accessToken);
if (result.error?.code === 'insufficient_scope') { return res.status(403).json({ error: 'insufficient_scope' });}
if (result.error) { return res.status(401).json({ error: 'invalid_token' });}
// Token is valid and has both scopes.カスタムクレームへのアクセス
Section titled “カスタムクレームへのアクセス”トークンには、認可サーバーによって追加されたカスタムクレーム(ロール、テナントIDなど)が含まれる場合があります。claimsオブジェクトを通じてアクセスします:
const result = await authrim.validateToken(accessToken);if (result.error) { throw new Error(result.error.message);}
// Access custom claims with type assertionconst roles = result.data.claims['roles'] as string[];const tenantId = result.data.claims['tenant_id'] as string;
// Or use a type parameter for full type safetyinterface MyTokenClaims extends AccessTokenClaims { roles: string[]; tenant_id: string;}
const claims = result.data.claims as MyTokenClaims;console.log(claims.roles); // ['admin', 'user']console.log(claims.tenant_id); // 'tenant-123'エラーコード
Section titled “エラーコード”validateToken() は代表的な検証失敗を result.error.code に以下のコードで返します。
| コード | 説明 | 代表的なHTTPステータス |
|---|---|---|
token_malformed | トークンがcompact JWTとして不正、またはparser limitを超過 | 401 |
algorithm_mismatch | トークンがalg: noneまたはサポートされていないアルゴリズムを使用 | 401 |
signature_invalid | 署名検証が失敗 | 401 |
token_expired | トークンのexpクレームがクロック許容値を超えて期限切れ | 401 |
token_not_yet_valid | トークンのnbfクレームがクロック許容値を超えて未来 | 401 |
invalid_issuer | トークンのissが設定されたissuerと一致しない | 401 |
invalid_audience | トークンのaudが設定されたaudienceと一致しない | 401 |
invalid_tenant | tenantクレームが欠落、不許可、またはtenant predicateで拒否 | 403 |
insufficient_scope | トークンに必要なスコープが1つ以上不足 | 403 |
jwks_key_not_found | トークンヘッダーに一致するJWKS keyが見つからない | 500 |
次のステップ
Section titled “次のステップ”- DPoP検証 — DPoPプルーフ検証による送信者制約トークンの検証
- JWKS管理 — 鍵のディスカバリ、キャッシュ、ローテーションの内部構造
- イントロスペクションと失効 — 認可サーバーでのトークンの問い合わせと失効
- セキュリティに関する考慮事項 — 本番セキュリティチェックリストとベストプラクティス