mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
docs(api): publish the factor-dependent reach of a step-up elevation
The contract now names which factors satisfy the fresh-factor routes and which do not, carries `satisfiesFreshFactor` on the mint response so a client can pick the ceremony before spending a proof, and describes the options endpoint's two ceremony kinds. The second-factor status read is documented as plain authentication — it carries no credential material, so it needs no elevation.
This commit is contained in:
1 parent
0991d754e4
commit
4cd0adc46d
3 files changed
+198
-32
No files matched your search
+122
-22
@@ -1605,11 +1605,18 @@ paths:
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
summary: Begin a passkey re-proof for a step-up elevation (Bearer only)
|
||||
description: "Returns SimpleWebAuthn assertion options scoped to the calling account's primary passkeys, plus a
|
||||
challenge id to present at POST /api/auth/step-up. Bearer-only: a cookie session is refused, because a browser
|
||||
re-proves its factor at login and carries the result on its session row. Returns 409 when the account has no
|
||||
passkey registered — use the password arm of the mint instead."
|
||||
summary: Begin a WebAuthn re-proof for a step-up elevation (Bearer only)
|
||||
description: "Returns SimpleWebAuthn assertion options plus a challenge id to present at POST /api/auth/step-up.
|
||||
`method: \"passkey\"` scopes the assertion to the account's primary passkeys; `method: \"webauthn\"` to its
|
||||
registered second-factor security keys. Bearer-only: a cookie session is refused, because a browser re-proves
|
||||
its factor at login and carries the result on its session row. Returns 409 when the account has no credential of
|
||||
the requested kind — fall back to another arm of the mint."
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/StepUpOptionsRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Assertion options issued.
|
||||
@@ -1632,26 +1639,34 @@ paths:
|
||||
- Auth
|
||||
summary: Mint a single-use step-up elevation (Bearer only)
|
||||
description: >-
|
||||
Re-prove the account password or a primary passkey and receive an opaque elevation that authorises exactly ONE
|
||||
second-factor-management call.
|
||||
Re-prove a factor and receive an opaque elevation that authorises exactly ONE second-factor-management call.
|
||||
|
||||
|
||||
The elevation is the Bearer transport's equivalent of the web's fresh-second-factor session stamp. It is bound
|
||||
to the exact token that minted it (another token, including the same account's, cannot redeem it), single-use,
|
||||
and valid for five minutes — the same window the cookie path uses. Present it as `X-Step-Up: hle_…` alongside
|
||||
the normal `Authorization: Bearer` header.
|
||||
WHICH factor you re-prove decides WHAT the elevation reaches. `password` reaches the same routes a plain cookie
|
||||
session reaches. `totp`, `webauthn`, and `passkey` additionally satisfy the fresh-factor routes — MFA disable,
|
||||
recovery-code regeneration, security-key removal — which is precisely the set of ceremonies for which the web
|
||||
marks a session second-factor-verified. The response carries `satisfiesFreshFactor` so a client can choose the
|
||||
right ceremony up front rather than discovering the refusal after spending a proof. A recovery code is NOT
|
||||
accepted here; an account that has lost its authenticator manages its second factor on the web.
|
||||
|
||||
|
||||
The elevation is bound to the exact token that minted it (another token, including the same account's, cannot
|
||||
redeem it), single-use, and valid for five minutes — the same window the cookie path uses. Present it as
|
||||
`X-Step-Up: hle_…` alongside the normal `Authorization: Bearer` header. It is spent only when the target route
|
||||
is about to act, so a 429, a 422, or a wrong code does not burn it.
|
||||
|
||||
|
||||
Presenting the token alone mints nothing: the body must carry a fresh factor proof. Every failure — wrong
|
||||
password, no password set on an SSO-provisioned account, an assertion for another account, a stale challenge —
|
||||
returns the same 401 with the same prose, and is audited server-side. Rate-limited per account (5 / 15 min) and
|
||||
per source address.
|
||||
password, no password set on an SSO-provisioned account, an assertion for another account, a stale challenge, a
|
||||
replayed TOTP step — returns the same 401 with the same prose, and is audited server-side. Rate-limited per
|
||||
account (5 / 15 min) and per source address.
|
||||
|
||||
|
||||
Accepting routes (the complete set): GET /api/auth/me/mfa; POST /api/auth/me/mfa/totp/setup; POST
|
||||
/api/auth/me/mfa/totp/confirm; POST /api/auth/me/mfa/disable; POST /api/auth/me/mfa/recovery-codes/regenerate;
|
||||
POST /api/auth/me/mfa/webauthn/register/options; POST /api/auth/me/mfa/webauthn/register/verify; PATCH and
|
||||
DELETE /api/auth/me/mfa/webauthn/{id}. Nothing else accepts one — admin endpoints stay cookie-only.
|
||||
Accepting routes (the complete set): POST /api/auth/me/mfa/totp/setup; POST /api/auth/me/mfa/totp/confirm; POST
|
||||
/api/auth/me/mfa/disable; POST /api/auth/me/mfa/recovery-codes/regenerate; POST
|
||||
/api/auth/me/mfa/webauthn/register/options; POST /api/auth/me/mfa/webauthn/register/verify; PATCH and DELETE
|
||||
/api/auth/me/mfa/webauthn/{id}. The last three of those and disable require a fresh-factor proof. GET
|
||||
/api/auth/me/mfa needs no elevation at all. Nothing else accepts one — admin endpoints stay cookie-only.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -1774,10 +1789,11 @@ paths:
|
||||
get:
|
||||
tags:
|
||||
- Auth
|
||||
summary: Second-factor status (cookie session or step-up elevation)
|
||||
summary: Second-factor status (cookie session or Bearer token)
|
||||
description: Whether TOTP is active, how many recovery codes remain, and the registered WebAuthn security keys. Metadata
|
||||
only — no secret, code, or public key. Accepts a cookie session, or a Bearer token presenting a single-use
|
||||
elevation from POST /api/auth/step-up in the `X-Step-Up` header; a Bearer token alone is still refused.
|
||||
only — no secret, no code, no public key, no credential id. Plain authentication (cookie session or
|
||||
cookie-equivalent token); unlike every mutation on this surface it needs no step-up elevation, because the
|
||||
payload carries no credential material.
|
||||
responses:
|
||||
"200":
|
||||
description: Second-factor status.
|
||||
@@ -11472,6 +11488,18 @@ components:
|
||||
- code
|
||||
- codeVerifier
|
||||
description: Exchange a one-time native OIDC handoff code (+ its PKCE verifier) for the standard native token bundle.
|
||||
StepUpOptionsRequest:
|
||||
type: object
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
enum:
|
||||
- passkey
|
||||
- webauthn
|
||||
description: "`passkey` begins an assertion against the account's primary passkeys; `webauthn` against its registered
|
||||
second-factor security keys."
|
||||
required:
|
||||
- method
|
||||
StepUpMintRequest:
|
||||
oneOf:
|
||||
- type: object
|
||||
@@ -11486,6 +11514,60 @@ components:
|
||||
required:
|
||||
- method
|
||||
- password
|
||||
- type: object
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
const: totp
|
||||
code:
|
||||
type: string
|
||||
pattern: ^\d{6}$
|
||||
required:
|
||||
- method
|
||||
- code
|
||||
- type: object
|
||||
properties:
|
||||
method:
|
||||
type: string
|
||||
const: webauthn
|
||||
challengeId:
|
||||
type: string
|
||||
minLength: 1
|
||||
credential:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
rawId:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
const: public-key
|
||||
response:
|
||||
type: object
|
||||
propertyNames:
|
||||
type: string
|
||||
additionalProperties: {}
|
||||
authenticatorAttachment:
|
||||
type: string
|
||||
enum:
|
||||
- platform
|
||||
- cross-platform
|
||||
clientExtensionResults:
|
||||
type: object
|
||||
propertyNames:
|
||||
type: string
|
||||
additionalProperties: {}
|
||||
required:
|
||||
- id
|
||||
- rawId
|
||||
- type
|
||||
- response
|
||||
description: SimpleWebAuthn ceremony response payload.
|
||||
required:
|
||||
- method
|
||||
- challengeId
|
||||
- credential
|
||||
- type: object
|
||||
properties:
|
||||
method:
|
||||
@@ -11529,7 +11611,10 @@ components:
|
||||
- method
|
||||
- challengeId
|
||||
- credential
|
||||
description: Re-prove the account password or a primary passkey to mint a single-use, token-bound step-up elevation.
|
||||
description: Re-prove a factor to mint a single-use, token-bound step-up elevation. `password` reaches the same routes a
|
||||
plain cookie session reaches; `totp`, `webauthn`, and `passkey` additionally satisfy the fresh-factor routes
|
||||
(disable, recovery-code rotation, security-key removal), matching exactly the ceremonies for which the web
|
||||
stamps a session second-factor-verified.
|
||||
type: object
|
||||
MfaDisableRequest:
|
||||
type: object
|
||||
@@ -15473,10 +15558,25 @@ components:
|
||||
type: integer
|
||||
minimum: -9007199254740991
|
||||
maximum: 9007199254740991
|
||||
method:
|
||||
type: string
|
||||
enum:
|
||||
- password
|
||||
- totp
|
||||
- webauthn
|
||||
- passkey
|
||||
description: The factor that was re-proved.
|
||||
satisfiesFreshFactor:
|
||||
type: boolean
|
||||
description: Whether this elevation reaches the fresh-factor routes (MFA disable, recovery-code regeneration,
|
||||
security-key removal). False for a password proof — mirroring the web, where a password login never marks a
|
||||
session second-factor-verified.
|
||||
required:
|
||||
- elevation
|
||||
- expiresAt
|
||||
- expiresInSeconds
|
||||
- method
|
||||
- satisfiesFreshFactor
|
||||
additionalProperties: false
|
||||
TotpSetupEnvelope:
|
||||
type: object
|
||||
|
||||
Reference in new issue
Block a user