概要
@authrim/server は7カテゴリにわたる27のエラーコードを持つ構造化されたエラーシステムを提供します。すべてのエラーにはHTTPステータス、一時的エラーの分類、リトライ可否のメタデータが含まれており、正しいエラーレスポンスを自動的に構築できます。
AuthrimServerError
SDKがスローするすべてのエラーは AuthrimServerError のインスタンスです:
import { AuthrimServerError } from '@authrim/server';
const token = await server.validateToken(accessToken);
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 }
プロパティ
| プロパティ | 型 | 説明 |
|---|
code | string | 機械可読なエラーコード(下記テーブル参照) |
message | string | 人間が読めるエラー説明 |
meta | AuthrimServerErrorMeta | 分類メタデータ |
| プロパティ | 型 | 説明 |
|---|
httpStatus | number | レスポンスに推奨されるHTTPステータスコード |
transient | boolean | エラーが一時的で自然に解消する可能性があるかどうか |
retryable | boolean | オペレーションを安全にリトライできるかどうか |
wwwAuthenticateError | string | undefined | WWW-Authenticate ヘッダー用のエラーコード(RFC 6750) |
エラーコードリファレンス
JWT検証エラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
invalid_token | 401 | いいえ | いいえ | トークンが無効(一般的な検証失敗) |
token_expired | 401 | いいえ | いいえ | トークンが期限切れ(expクレーム) |
token_not_yet_valid | 401 | いいえ | いいえ | トークンがまだ有効ではない(nbfクレーム) |
token_malformed | 401 | いいえ | いいえ | トークンをデコードまたはパースできない |
signature_invalid | 401 | いいえ | いいえ | JWT署名の検証に失敗 |
algorithm_mismatch | 401 | いいえ | いいえ | トークンのアルゴリズムが期待されるアルゴリズムと一致しない |
Issuer / Audienceエラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
invalid_issuer | 401 | いいえ | いいえ | トークンのissuerが期待される値と一致しない |
invalid_audience | 401 | いいえ | いいえ | トークンのaudienceに期待される値が含まれていない |
JWKSエラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
jwks_fetch_error | 502 | はい | はい | JWKSドキュメントの取得に失敗 |
jwks_key_not_found | 401 | いいえ | いいえ | トークンのkidに一致するキーがJWKSに見つからない |
jwks_key_ambiguous | 401 | いいえ | いいえ | トークンのkidに一致するキーが複数存在する |
jwks_key_import_error | 500 | いいえ | いいえ | 署名検証用のJWKインポートに失敗 |
DPoPエラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
dpop_proof_missing | 401 | いいえ | いいえ | DPoPプルーフヘッダーが欠落 |
dpop_proof_invalid | 401 | いいえ | いいえ | DPoPプルーフが不正または無効 |
dpop_proof_signature_invalid | 401 | いいえ | いいえ | DPoPプルーフの署名検証に失敗 |
dpop_method_mismatch | 401 | いいえ | いいえ | DPoPプルーフ内のHTTPメソッドがリクエストと一致しない |
dpop_uri_mismatch | 401 | いいえ | いいえ | DPoPプルーフ内のURIがリクエストURLと一致しない |
dpop_ath_mismatch | 401 | いいえ | いいえ | DPoPプルーフ内のアクセストークンハッシュが一致しない |
dpop_binding_mismatch | 401 | いいえ | いいえ | DPoPプルーフのキーがトークンバインディングと一致しない |
dpop_iat_expired | 401 | いいえ | いいえ | DPoPプルーフのiatが古すぎる |
dpop_nonce_required | 401 | いいえ | いいえ | サーバーがDPoP nonceを要求しているが提供されていない |
オペレーションエラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
introspection_error | 502 | はい | はい | トークンイントロスペクションリクエストが失敗 |
revocation_error | 502 | はい | はい | トークン失効リクエストが失敗 |
設定エラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
configuration_error | 500 | いいえ | いいえ | 無効なSDK設定 |
provider_error | 500 | いいえ | いいえ | プロバイダー実装エラー |
ネットワークエラー
| コード | HTTPステータス | 一時的 | リトライ可 | 説明 |
|---|
network_error | 502 | はい | はい | ネットワークリクエストが失敗 |
timeout_error | 504 | はい | はい | リクエストがタイムアウト |
レスポンスユーティリティ
RFC 6750準拠の WWW-Authenticate ヘッダー値を生成します:
import { buildWwwAuthenticateHeader } from '@authrim/server';
const header = buildWwwAuthenticateHeader(error, {
// Bearer realm="my-api", error="invalid_token", error_description="Token has expired"
オプション:
| オプション | 型 | 説明 |
|---|
realm | string | ヘッダーのRealm値 |
buildErrorResponse()
HTTPレスポンスに適したJSONエラーボディを生成します:
import { buildErrorResponse } from '@authrim/server';
const body = buildErrorResponse(error);
// error: 'invalid_token',
// error_description: 'Token has expired'
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';
authrimMiddleware(server, {
// Log to your monitoring service
httpStatus: error.meta.httpStatus,
transient: error.meta.transient,
metrics.increment('auth.error', { code: error.code });
フレームワーク固有のエラーパターン
Express
} from '@authrim/server';
app.get('/api/resource', async (req, res) => {
const token = await server.validateToken(
req.headers.authorization?.replace('Bearer ', '') ?? '',
res.json({ data: getResource(token.sub) });
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) => {
const token = await server.validateToken(
c.req.header('authorization')?.replace('Bearer ', '') ?? '',
return c.json({ data: getResource(token.sub) });
if (error instanceof AuthrimServerError) {
return c.json(buildErrorResponse(error), error.meta.httpStatus);
return c.json({ error: 'internal_error' }, 500);
一時的エラーのリトライ戦略
一時的エラー(ネットワーク障害、JWKSフェッチ失敗)はリトライ可能です。meta.transient と meta.retryable フラグを使用してリトライロジックを構築してください:
import { AuthrimServerError } from '@authrim/server';
async function validateWithRetry(
): Promise<ValidatedToken> {
let lastError: AuthrimServerError | undefined;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
return await server.validateToken(token);
if (!(error instanceof AuthrimServerError)) throw error;
// Only retry transient, retryable errors
if (!error.meta.retryable || attempt === maxRetries) {
// Exponential backoff: 100ms, 200ms, 400ms
const delay = 100 * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
一時的エラー vs 非一時的エラーのまとめ
| カテゴリ | 一時的 | リトライ可 | 対処方法 |
|---|
| JWT検証 | いいえ | いいえ | 即座に401を返す |
| Issuer/Audience | いいえ | いいえ | 即座に401を返す |
| DPoP | いいえ | いいえ | 即座に401を返す |
| JWKSフェッチ | はい | はい | バックオフでリトライ |
| オペレーション(イントロスペクション/失効) | はい | はい | バックオフでリトライ |
| ネットワーク | はい | はい | バックオフでリトライ |
| 設定 | いいえ | いいえ | 設定を修正して再起動 |
次のステップ