コンテンツにスキップ

トークン検証

概要

トークン検証は@authrim/serverの中核機能です。validateToken()メソッドは、JWTの解析、署名鍵の取得、署名の検証、すべての標準クレームのチェックという完全な検証パイプラインを実行します。

validateToken API

const result = await authrim.validateToken(token, options?);

パラメータ

パラメータ説明
tokenstring生のJWTアクセストークン(Bearerプレフィックスなし)
optionsTokenValidationOptionsオプションの検証オプション

TokenValidationOptions

interface TokenValidationOptions {
requiredScopes?: string[];
requiredClaims?: string[];
}
オプション説明
requiredScopesstring[]トークンのscopeクレームに存在する必要があるスコープ
requiredClaimsstring[]トークンペイロードに存在する必要があるクレーム名

戻り値: ValidatedToken

interface ValidatedToken {
claims: AccessTokenClaims;
token: string;
tokenType: 'Bearer' | 'DPoP';
expiresIn?: number;
}
フィールド説明
claimsAccessTokenClaims解析・検証済みのJWTクレーム
tokenstring元のトークン文字列
tokenType'Bearer' | 'DPoP'クレームに基づいて検出されたトークンタイプ
expiresInnumber | undefinedトークンの有効期限までの秒数(expから計算)

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
}

検証パイプライン

SDKは以下のパイプラインでトークンを検証します。トークンが受け入れられるには、各ステップをパスする必要があります。

flowchart TD
    A["JWT文字列を受信"] --> B["サイズチェック
(最大 8 KB)"] B --> C["JWTを解析
(Header + Payload + Signature)"] C --> D["アルゴリズムチェック
(alg: none を拒否)"] D --> E["署名鍵を取得
(JWKS by kid)"] E --> F["署名を検証
(RS/PS/ES/EdDSA)"] F --> G["issを検証
(タイミングセーフ)"] G --> H["audを検証
(タイミングセーフ)"] H --> I["expを検証
(+ クロック許容値)"] I --> J["nbfを検証
(+ クロック許容値)"] J --> K["iatを検証
(未来でないこと)"] K --> L["必要なスコープをチェック"] L --> M["必要なクレームをチェック"] M --> N["トークンタイプを検出
(Bearer vs DPoP)"] N --> O["ValidatedTokenを返却"]

いずれかのステップが失敗した場合、SDKは特定のエラーをスローします。以下のエラータイプセクションを参照してください。

サポートされるアルゴリズム

SDKは署名検証に以下のJWSアルゴリズムをサポートしています:

アルゴリズム鍵タイプ曲線 / サイズ説明
RS256RSA2048+ビットRSASSA-PKCS1-v1_5 with SHA-256
RS384RSA2048+ビットRSASSA-PKCS1-v1_5 with SHA-384
RS512RSA2048+ビットRSASSA-PKCS1-v1_5 with SHA-512
PS256RSA2048+ビットRSASSA-PSS with SHA-256
PS384RSA2048+ビットRSASSA-PSS with SHA-384
PS512RSA2048+ビットRSASSA-PSS with SHA-512
ES256ECP-256ECDSA with SHA-256
ES384ECP-384ECDSA with SHA-384
ES512ECP-521ECDSA with SHA-512
EdDSAOKPEd25519Edwards-curve Digital Signature

クレーム検証の詳細

発行者(iss

issクレームは、設定されたissuer値のいずれかと正確に一致する必要があります。比較にはサイドチャネル攻撃を防止するためにタイミングセーフアルゴリズムが使用されます。

// Single issuer
const authrim = new AuthrimServer({
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
});
// Multiple issuers
const authrim = new AuthrimServer({
issuer: [
'https://auth.example.com',
'https://auth.partner.com',
],
audience: 'https://api.example.com',
});

オーディエンス(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

expクレームは、現在時刻にclockToleranceSecondsを加えた値と照合されます:

token is valid if: exp + clockToleranceSeconds > now

デフォルトの許容値60秒では、最大60秒前に期限切れになったトークンでも受け入れられます。

有効開始時刻(nbf

存在する場合、nbfクレームは現在時刻からclockToleranceSecondsを引いた値と照合されます:

token is valid if: nbf - clockToleranceSeconds <= now

発行時刻(iat

iatクレームは、トークンが未来に発行されていないことをサニティチェックします(クロック許容値を考慮):

token is valid if: iat - clockToleranceSeconds <= now

スコープ検証

requiredScopesオプションを使用して必要なスコープを適用します:

// Require specific scopes
const result = await authrim.validateToken(token, {
requiredScopes: ['read:users', 'write:users'],
});

SDKは、指定されたすべてのスコープがトークンのscopeクレーム(スペース区切り文字列)に存在するかをチェックします。必要なスコープが1つでも欠けている場合、InsufficientScopeErrorがスローされます。

BearerとDPoPの自動検出

SDKはcnf(confirmation)クレームに基づいてトークンタイプを自動検出します:

  • トークンにcnf.jkt(JWK Thumbprint)が含まれている場合、トークンはDPoPとして分類されます
  • それ以外の場合、トークンはBearerとして分類されます
const result = await authrim.validateToken(token);
if (result.tokenType === 'DPoP') {
// This token is sender-constrained — validate the DPoP proof too
await authrim.validateDPoP(dpopProof, {
accessTokenHash: computeHash(token),
expectedThumbprint: result.claims.cnf!.jkt!,
method: 'GET',
url: 'https://api.example.com/resource',
});
}

完全なDPoP検証については、DPoP検証を参照してください。

コード例

基本的なトークン検証

import { AuthrimServer } from '@authrim/server';
const authrim = new AuthrimServer({
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
});
await authrim.init();
try {
const result = await authrim.validateToken(accessToken);
console.log('User:', result.claims.sub);
console.log('Scopes:', result.claims.scope);
console.log('Expires in:', result.expiresIn, 'seconds');
} catch (error) {
console.error('Token validation failed:', error.message);
}

必要なスコープ付き

try {
const result = await authrim.validateToken(accessToken, {
requiredScopes: ['read:orders', 'write:orders'],
});
// Token is valid and has both scopes
} catch (error) {
if (error.name === 'InsufficientScopeError') {
// Token is valid but missing required scopes — return 403
return res.status(403).json({ error: 'insufficient_scope' });
}
// Token is invalid — return 401
return res.status(401).json({ error: 'invalid_token' });
}

カスタムクレームへのアクセス

トークンには、認可サーバーによって追加されたカスタムクレーム(ロール、テナントIDなど)が含まれる場合があります。claimsオブジェクトを通じてアクセスします:

const result = await authrim.validateToken(accessToken);
// Access custom claims with type assertion
const roles = result.claims['roles'] as string[];
const tenantId = result.claims['tenant_id'] as string;
// Or use a type parameter for full type safety
interface MyTokenClaims extends AccessTokenClaims {
roles: string[];
tenant_id: string;
}
const claims = result.claims as MyTokenClaims;
console.log(claims.roles); // ['admin', 'user']
console.log(claims.tenant_id); // 'tenant-123'

エラータイプ

エラー説明HTTPステータス
InsecureAlgorithmErrorトークンがalg: noneまたはサポートされていないアルゴリズムを使用401
InvalidSignatureError署名検証が失敗401
TokenExpiredErrorトークンのexpクレームが経過(クロック許容値を超過)401
TokenNotYetValidErrorトークンのnbfクレームが未来(クロック許容値を超過)401
InvalidIssuerErrorトークンのissが設定された発行者と一致しない401
InvalidAudienceErrorトークンのaudが設定されたオーディエンスと一致しない401
InsufficientScopeErrorトークンに必要なスコープが1つ以上不足403
MissingClaimErrorトークンに必要なクレームが不足401
JwksErrorJWKSの取得または処理に失敗500
TokenSizeLimitErrorトークンが8 KBサイズ制限を超過401

次のステップ