diff --git a/docs/claims-contract.ja.md b/docs/claims-contract.ja.md index b933583..c3a2099 100644 --- a/docs/claims-contract.ja.md +++ b/docs/claims-contract.ja.md @@ -21,6 +21,7 @@ RFC 9068 JWT access token。provider は `generateToken`(auth.provider の `pa | `iss` | デプロイ設定の issuer。必須、リクエスト由来にしない。 | jose 検証でピン — `oauth.jwt.issuer` / `OAUTH_JWT_ISSUER`。 | デプロイの identity。 | | `typ`(header) | access token は `at+jwt`(RFC 9068)、refresh token は `rt+jwt`、ID token(wire 名 `id_token`)は auth.provider v0.10.0 以降は標準の `JWT`(それ以前は非標準の `id+jwt` で、`typ` を厳格に検証する外部 RP に弾かれていた)。auth.provider#402(2026-08-30)で移行期間は終了し、現在は `JWT` のみを受理する。 | `oauth.jwt.tokenType`、default `at+jwt`。比較時に `application/` prefix は無視。 | 3 種の token を区別する **唯一の** 判別子 — このピンが、同じ鍵で署名された refresh / id token が `/verify` を通ることを防いでいる。防いでいる実体は **`at+jwt` と互いに素であること** であり、`JWT` は `id+jwt` と同様にこれを満たす。claim レベルの代替チェックは存在しない。 | | `exp` / `iat` | 常に刻印(`core/src/grants/token.mts`)。 | 両方必須(`tokenAuthenticator` の必須 claim チェック + 常設の `maxTokenAgeSeconds` 上限)。`exp` のない token は永続 credential として拒否。 | 寿命。verifier は issuer の規律を信頼せず、issuer の `exp` をさらに上限で抑える。 | +| `amr` / `acr` | ユーザーがどう認証したか、どの保証レベルを満たしたか([auth.provider#481](https://github.com/o3co/auth.provider/issues/481))。`amr` はセッションが記録した RFC 8176 のメソッド列 — パスキーなら `["hwk"]` — で、`authorization_code`・`session`・WebAuthn の各 grant が刻印する。`acr` は `/authorize` が `acr_values` から満たした値で、`authorization_code` だけが刻印する。どちらも refresh token に載り、refresh は再認証ではないので、refresh が発行するすべての token に引き継がれる(`oauth/src/grants/refreshToken.mts`)。刻印されるのは形の正しい値だけ: `amr` は空でない文字列の空でない配列、`acr` は空でない文字列(`core/src/grants/authenticationClaims.mts`)。それ以外は省かれ、空で送られることはない。 | 組み込み collector は読まない。これらでゲートするデプロイは、検証済み claim から自前の attribute キーへの `PayloadClaimAttributeCollector` マッピング(`packages/builtins`)を宣言し、Rule を書く。 | **元の**認証イベント。`auth_time` と同じ(OIDC Core §12.2)— refresh された access token が示すのは、それが連なるログインであって refresh ではない。無いことは provider が何も記録しなかったことを意味し、ユーザーが第二要素を使わなかったという表明ではない。 | ## 境界を越えない claim diff --git a/docs/claims-contract.md b/docs/claims-contract.md index 8e63abd..b91fd64 100644 --- a/docs/claims-contract.md +++ b/docs/claims-contract.md @@ -21,6 +21,7 @@ Path convention for the tables below: paths in the *Provider writes* column are | `iss` | Deployment-configured issuer; required, never request-derived. | Pinned by jose verification — `oauth.jwt.issuer` / `OAUTH_JWT_ISSUER`. | Deployment identity. | | `typ` (header) | `at+jwt` on access tokens (RFC 9068), `rt+jwt` on refresh tokens, and the standard `JWT` on ID tokens (wire name `id_token`) since auth.provider v0.10.0 — it was the nonstandard `id+jwt` before, which strict external RPs rejected; auth.provider#402 (2026-08-30) closed the dual-accept window, so only `JWT` is accepted now. | `oauth.jwt.tokenType`, default `at+jwt`; an `application/` prefix on either side is ignored when comparing. | The **only** discriminator between the three token kinds — the pin is what keeps a refresh or id token signed with the same key from passing `/verify`. What does the keeping-out is being **disjoint from `at+jwt`**, which `JWT` satisfies exactly as `id+jwt` did. There is no claim-level fallback check. | | `exp` / `iat` | Always stamped (`core/src/grants/token.mts`). | Both required (`tokenAuthenticator`'s required-claims check + the always-set `maxTokenAgeSeconds` bound); a token without `exp` is refused as a permanent credential. | Lifetime. The verifier additionally caps the issuer's `exp` rather than trusting issuer discipline. | +| `amr` / `acr` | How, and to which assurance level, the user authenticated ([auth.provider#481](https://github.com/o3co/auth.provider/issues/481)). `amr` is the RFC 8176 method list the session recorded — `["hwk"]` for a passkey — stamped by the `authorization_code`, `session` and WebAuthn grants; `acr` is the value `/authorize` satisfied from `acr_values`, stamped by `authorization_code` only. Both travel on the refresh token and are carried onto every token a refresh mints, since a refresh does not re-authenticate (`oauth/src/grants/refreshToken.mts`). Only well-formed values are stamped: `amr` a non-empty array of non-empty strings, `acr` a non-empty string (`core/src/grants/authenticationClaims.mts`); anything else is omitted, never sent empty. | No built-in collector reads them. A deployment that gates on them declares a `PayloadClaimAttributeCollector` mapping (`packages/builtins`) from the verified claim to an attribute key of its own, and writes the rule. | The **original** authentication event, as `auth_time` is (OIDC Core §12.2) — a refreshed access token reports the login it descends from, not the refresh. Absent means the provider recorded none; it is not a statement that the user did not use a second factor. | ## Claims that do NOT cross