Errors、rate limit、retry、冪等性#

この文書では、Management API / Public Authentication API の Problem Details、OIDC error、rate limit、write の再送方法を説明する。

Problem Details#

Management API と Public Authentication API のエラーは RFC 9457 Problem Details を application/problem+json として返す。標準 member に加えて code と request_id を拡張 field として含める。成功・失敗を問わず応答には X-Request-Id header が付く。

{
  "type": "https://docs.example-auth.com/errors/invalid-request",
  "title": "Bad Request",
  "status": 400,
  "detail": "<入力エラーの説明>",
  "code": "invalid_request",
  "request_id": "req_<request-id>"
}

code は機械判定用の安定した key であり、detail、title、type URI の末尾文字列を分岐条件にしない。detail は診断用で、省略される場合がある。request_id をサポート問い合わせとログ照合に使う。

type は URI 識別子である。処理の分岐には code を使う。

OAuth error#

OIDC /oauth2/token の OAuth error は Problem Details ではなく、OAuth 2.0 JSON response として返る。

{
  "error": "invalid_client"
}

error_description は省略可能で、応答には X-Request-Id header が付く。契約上の error code は次のとおりである。

Code 意味
invalid_request token / authorize request の形式不正
invalid_client Client 認証失敗
invalid_grant code、redirect URI、PKCE verifier、または refresh token が無効
unsupported_grant_type 未対応の grant
invalid_scope 不許可 scope
access_denied 認可拒否
server_error サーバー側エラー
temporarily_unavailable 一時的な利用不可

/oauth2/authorize の malformed request は JSON の invalid_request として返る。他の authorize failure が Hosted Login の /error?reason=... へ遷移する場合もある。OAuth error response を常に Client の redirect URI へ返す前提にしない。

Rate limit#

Rate limit は Environment / Client / IP / email / challenge / credential / Management API key / Workspace などの key scope で分離する。既定値は次のとおりである。

Endpoint / scope Limit
OTP start / IP 10 回 / 10 分
OTP start / email 5 回 / 30 分
OTP verify / challenge 5 回まで
Passkey options / IP 30 回 / 分
Passkey verify / credential 10 回 / 分
Social start / IP 30 回 / 10 分
Token endpoint / Client 120 回 / 分
Management API / key 600 回 / 分
User search / Workspace 120 回 / 分

超過時は HTTP 429 を返す。Retry-After は待機秒数を表す。時間窓の limit では窓の秒数、challenge ごとの累積回数 limit では 0 となる。rate-limit Problem Details の code は rate_limited であり、X-Request-Id も返る。middleware が返す 429 には同じ値を retry_after_seconds extension にも含める。OTP start の service-level error response は extension を含めない場合があるため、header を正とする。RateLimit-Limit / RateLimit-Remaining は返さない。

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 0
X-Request-Id: req_<request-id>

{
  "type": "https://docs.example-auth.com/errors/rate-limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "request_id": "req_<request-id>",
  "retry_after_seconds": 0
}

Retry-After に従って待つ。OTP verify の challenge 上限は累積 limit なので、時間を置いても同じ challenge を再利用できない。

Retry#

Problem Details に retry 可否を示す field はない。HTTP 429 は Retry-After を使う。HTTP 5xx は一時障害の可能性があるが、処理が再実行安全な場合だけ bounded backoff で retry する。入力不正、Client 認証失敗、invalid_grant などの 4xx は同じ要求を繰り返しても解消しない。

OIDC authorization code は一度だけ交換できる。Token endpoint 呼び出しの結果が不明な場合に同じ code を無制限に retry せず、新しい認可フローを開始する。BFF の @auth-platform/server は一時的な refresh failure で local session を直ちに破棄せず、invalid_grant では session を破棄する。

Error Retry 方針
OAuth server_error / temporarily_unavailable Server SDK は transient error として扱う。bounded backoff を使い、BFF refresh 中に session を即破棄しない。
Management API idempotency_store_unavailable (503) 同じ Idempotency-Key と同じ body で write を retry する。
Public Authentication API user_unavailable (503) 一時障害である。再認証せず、bounded backoff で retry する。
invalid_grant、入力 validation error、invalid_client 同じ要求を retry しない。Authorization code 交換の結果が不明なら、SDK の結果に従い、必要に応じて新しい認可フローを開始する。

Management API write の Idempotency-Key#

POST / PATCH / DELETE に Idempotency-Key header を付けられる。空でない 255 文字以下の値を使う。記録は Workspace と route と key の組み合わせで分離される。初回 response が保存された後、同じ method・path/query・canonical JSON body の再送では保存済み response を返し、write handler を再実行しない。同じ key を異なる要求に使うと 409 idempotency_key_conflict の Problem Details を返す。5xx response は retry 可能性を残すため保存対象にしない。

Idempotency-Key: create-client-<unique-operation-id>

同じ論理操作を timeout 後に再送する場合は、同じ key と同じ request body を使う。JSON object の property 順序だけが異なる場合、canonicalization により conflict にはならない。method、path/query、body が異なる要求には新しい key を発行する。