コンテンツにスキップ

エラーハンドリング

概要

@authrim/server は7カテゴリにわたる27のエラーコードを持つ構造化されたエラーシステムを提供します。すべてのエラーにはHTTPステータス、一時的エラーの分類、リトライ可否のメタデータが含まれており、正しいエラーレスポンスを自動的に構築できます。

AuthrimServerError

SDKがスローするすべてのエラーは AuthrimServerError のインスタンスです:

import { AuthrimServerError } from '@authrim/server';
try {
const token = await server.validateToken(accessToken);
} catch (error) {
if (error instanceof AuthrimServerError) {
console.log(error.code); // e.g., 'token_expired'
console.log(error.message); // Human-readable description
console.log(error.meta); // { httpStatus, transient, retryable, wwwAuthenticateError }
}
}

プロパティ

プロパティ説明
codestring機械可読なエラーコード(下記テーブル参照)
messagestring人間が読めるエラー説明
metaAuthrimServerErrorMeta分類メタデータ

AuthrimServerErrorMeta

プロパティ説明
httpStatusnumberレスポンスに推奨されるHTTPステータスコード
transientbooleanエラーが一時的で自然に解消する可能性があるかどうか
retryablebooleanオペレーションを安全にリトライできるかどうか
wwwAuthenticateErrorstring | undefinedWWW-Authenticate ヘッダー用のエラーコード(RFC 6750)

エラーコードリファレンス

JWT検証エラー

コードHTTPステータス一時的リトライ可説明
invalid_token401いいえいいえトークンが無効(一般的な検証失敗)
token_expired401いいえいいえトークンが期限切れ(expクレーム)
token_not_yet_valid401いいえいいえトークンがまだ有効ではない(nbfクレーム)
token_malformed401いいえいいえトークンをデコードまたはパースできない
signature_invalid401いいえいいえJWT署名の検証に失敗
algorithm_mismatch401いいえいいえトークンのアルゴリズムが期待されるアルゴリズムと一致しない

Issuer / Audienceエラー

コードHTTPステータス一時的リトライ可説明
invalid_issuer401いいえいいえトークンのissuerが期待される値と一致しない
invalid_audience401いいえいいえトークンのaudienceに期待される値が含まれていない

JWKSエラー

コードHTTPステータス一時的リトライ可説明
jwks_fetch_error502はいはいJWKSドキュメントの取得に失敗
jwks_key_not_found401いいえいいえトークンのkidに一致するキーがJWKSに見つからない
jwks_key_ambiguous401いいえいいえトークンのkidに一致するキーが複数存在する
jwks_key_import_error500いいえいいえ署名検証用のJWKインポートに失敗

DPoPエラー

コードHTTPステータス一時的リトライ可説明
dpop_proof_missing401いいえいいえDPoPプルーフヘッダーが欠落
dpop_proof_invalid401いいえいいえDPoPプルーフが不正または無効
dpop_proof_signature_invalid401いいえいいえDPoPプルーフの署名検証に失敗
dpop_method_mismatch401いいえいいえDPoPプルーフ内のHTTPメソッドがリクエストと一致しない
dpop_uri_mismatch401いいえいいえDPoPプルーフ内のURIがリクエストURLと一致しない
dpop_ath_mismatch401いいえいいえDPoPプルーフ内のアクセストークンハッシュが一致しない
dpop_binding_mismatch401いいえいいえDPoPプルーフのキーがトークンバインディングと一致しない
dpop_iat_expired401いいえいいえDPoPプルーフのiatが古すぎる
dpop_nonce_required401いいえいいえサーバーがDPoP nonceを要求しているが提供されていない

オペレーションエラー

コードHTTPステータス一時的リトライ可説明
introspection_error502はいはいトークンイントロスペクションリクエストが失敗
revocation_error502はいはいトークン失効リクエストが失敗

設定エラー

コードHTTPステータス一時的リトライ可説明
configuration_error500いいえいいえ無効なSDK設定
provider_error500いいえいいえプロバイダー実装エラー

ネットワークエラー

コードHTTPステータス一時的リトライ可説明
network_error502はいはいネットワークリクエストが失敗
timeout_error504はいはいリクエストがタイムアウト

レスポンスユーティリティ

buildWwwAuthenticateHeader()

RFC 6750準拠の WWW-Authenticate ヘッダー値を生成します:

import { buildWwwAuthenticateHeader } from '@authrim/server';
const header = buildWwwAuthenticateHeader(error, {
realm: 'my-api',
});
// Example output:
// Bearer realm="my-api", error="invalid_token", error_description="Token has expired"

オプション:

オプション説明
realmstringヘッダーのRealm値

buildErrorResponse()

HTTPレスポンスに適したJSONエラーボディを生成します:

import { buildErrorResponse } from '@authrim/server';
const body = buildErrorResponse(error);
// {
// error: 'invalid_token',
// error_description: 'Token has expired'
// }

buildErrorHeaders()

WWW-Authenticate を含むレスポンスヘッダーを生成します:

import { buildErrorHeaders } from '@authrim/server';
const headers = buildErrorHeaders(error, { realm: 'my-api' });
// {
// 'WWW-Authenticate': 'Bearer realm="my-api", error="invalid_token", ...',
// 'Content-Type': 'application/json'
// }

ミドルウェアでのエラーハンドリング

すべてのフレームワークアダプターは、ロギングとモニタリングのための onError コールバックを受け付けます:

import { authrimMiddleware } from '@authrim/server/adapters/express';
app.use(
'/api',
authrimMiddleware(server, {
realm: 'my-api',
onError: (error) => {
// Log to your monitoring service
logger.warn({
code: error.code,
message: error.message,
httpStatus: error.meta.httpStatus,
transient: error.meta.transient,
});
// Track metrics
metrics.increment('auth.error', { code: error.code });
},
}),
);

フレームワーク固有のエラーパターン

Express

import {
AuthrimServerError,
buildErrorResponse,
buildErrorHeaders,
} from '@authrim/server';
app.get('/api/resource', async (req, res) => {
try {
const token = await server.validateToken(
req.headers.authorization?.replace('Bearer ', '') ?? '',
);
res.json({ data: getResource(token.sub) });
} catch (error) {
if (error instanceof AuthrimServerError) {
const headers = buildErrorHeaders(error, { realm: 'my-api' });
const body = buildErrorResponse(error);
return res.status(error.meta.httpStatus).set(headers).json(body);
}
res.status(500).json({ error: 'internal_error' });
}
});

Hono

import { AuthrimServerError, buildErrorResponse } from '@authrim/server';
app.get('/api/resource', async (c) => {
try {
const token = await server.validateToken(
c.req.header('authorization')?.replace('Bearer ', '') ?? '',
);
return c.json({ data: getResource(token.sub) });
} catch (error) {
if (error instanceof AuthrimServerError) {
return c.json(buildErrorResponse(error), error.meta.httpStatus);
}
return c.json({ error: 'internal_error' }, 500);
}
});

一時的エラーのリトライ戦略

一時的エラー(ネットワーク障害、JWKSフェッチ失敗)はリトライ可能です。meta.transientmeta.retryable フラグを使用してリトライロジックを構築してください:

import { AuthrimServerError } from '@authrim/server';
async function validateWithRetry(
server: AuthrimServer,
token: string,
maxRetries = 3,
): Promise<ValidatedToken> {
let lastError: AuthrimServerError | undefined;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await server.validateToken(token);
} catch (error) {
if (!(error instanceof AuthrimServerError)) throw error;
lastError = error;
// Only retry transient, retryable errors
if (!error.meta.retryable || attempt === maxRetries) {
throw error;
}
// Exponential backoff: 100ms, 200ms, 400ms
const delay = 100 * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw lastError;
}

一時的エラー vs 非一時的エラーのまとめ

カテゴリ一時的リトライ可対処方法
JWT検証いいえいいえ即座に401を返す
Issuer/Audienceいいえいいえ即座に401を返す
DPoPいいえいいえ即座に401を返す
JWKSフェッチはいはいバックオフでリトライ
オペレーション(イントロスペクション/失効)はいはいバックオフでリトライ
ネットワークはいはいバックオフでリトライ
設定いいえいいえ設定を修正して再起動

次のステップ