Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/types-0-30-0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'seamless-auth-api': minor
---

Moves to `@seamless-auth/types` 0.30.0.

- OAuth provider config is refused at request validation when `clientSecretEnv` does not end in `_CLIENT_SECRET` or a provider URL is not `http(s)`, the same rules 0.19.4 enforced after parsing. The production-only checks (https, public destinations) stay in the server.
- New system config keys `recovery_codes` (`RECOVERY_CODES`, default `{"enabled":true,"requireAtEnrollment":false}`) and `account_recovery` (`ACCOUNT_RECOVERY`, default `{"enabled":false,"delay":"24h"}`), seeded at boot and patchable. The recovery features that read them arrive in this release.
4 changes: 4 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ first boot.
| `SESSION_IDLE_TTL` | No | `8h` | `session_idle_ttl` | Format `\d+[smhd]`. How long a session may go unrefreshed. The absolute session lifetime is `REFRESH_TOKEN_TTL`, measured from sign-in and not extended by refresh; this only binds while it is the shorter of the two. |
| `MAX_CONCURRENT_SESSIONS` | No | unlimited | `max_concurrent_sessions` | How many sessions one user may hold at once. Unset, empty, `null`, `none` or `unlimited` all mean no cap, which is the default. When a signed-in user is at the limit, the oldest session is revoked to make room and a `session_evicted` auth event is recorded; the sign-in itself always succeeds. Lowering the limit converges on each user's next sign-in rather than one session per login. NIST 800-53 AC-10. |
| `AUTHENTICATOR_POLICY` | No | `{"attachment":"any","userVerification":"required","attestation":"none","requireKnownAuthenticator":false,"syncedPasskeys":"allow","aaguidAllowList":[],"aaguidDenyList":[]}` | `authenticator_policy` | JSON. `attachment` is `any`, `platform` or `cross-platform`; `any` offers both built-in authenticators and roaming security keys, and naming one narrows the browser picker and rejects a request asking for the other. `userVerification` is `required`, `preferred` or `discouraged` and drives both what the browser is asked for and what the server enforces. `attestation` is `none` or `direct`; `direct` asks the authenticator to identify itself, which is what enables validation against the FIDO Metadata Service, and carries a privacy cost so it is off unless needed. `requireKnownAuthenticator` refuses an authenticator the metadata service does not list, and only applies under `direct`. It also refuses a credential that self attests or presents no attestation, since neither can be looked up, so it rules out authenticators that ship no attestation certificate. Changing `attestation` needs a restart, because the metadata service is prepared at startup. `syncedPasskeys` is `allow` or `block`; `allow`, the default, enrols a credential that can leave the device it was created on, which includes every iCloud Keychain and Google Password Manager passkey, so a stock instance accepts the passkey a normal device offers. `block` refuses those, which is what a deployment issuing its own authenticators wants. `aaguidAllowList` and `aaguidDenyList` restrict which authenticator models may register, and need `attestation` set to `direct` to mean anything. |
| `RECOVERY_CODES` | No | `{"enabled":true,"requireAtEnrollment":false}` | `recovery_codes` | JSON. Single-use recovery codes. A user has codes only after generating a set, so `enabled` matters once someone has. `requireAtEnrollment` asks for a set during first passkey enrollment. Recovery codes are not a login method, so `LOGIN_METHODS` cannot turn them off. |
| `ACCOUNT_RECOVERY` | No | `{"enabled":false,"delay":"24h"}` | `account_recovery` | JSON. Self-service recovery through a verified email or phone. Off by default. It completes only after `delay` (`1h` to `30d`), and every other channel and session is told so the owner can cancel. |

#### `/login` response timing

Expand Down Expand Up @@ -401,6 +403,8 @@ Validation is enforced by [`systemConfig.schema.ts`](../src/schemas/systemConfig
| `oauth_providers` | provider[] | `OAUTH_PROVIDERS` | `[]` |
| `lockout_policy` | object | `LOCKOUT_POLICY` | `{enabled,maxFailures:10,windowSeconds:900,lockoutSeconds:900}` |
| `authenticator_policy` | object | `AUTHENTICATOR_POLICY` | `{attachment:"any",userVerification:"required",attestation:"none",requireKnownAuthenticator:false,syncedPasskeys:"allow",aaguidAllowList:[],aaguidDenyList:[]}` |
| `recovery_codes` | object | `RECOVERY_CODES` | `{enabled:true,requireAtEnrollment:false}` |
| `account_recovery` | object | `ACCOUNT_RECOVERY` | `{enabled:false,delay:"24h"}` |
| `session_idle_ttl` | string (`\d+[smhd]`) | `SESSION_IDLE_TTL` | `8h` |
| `max_concurrent_sessions` | number or null | `MAX_CONCURRENT_SESSIONS` | `null` (no limit) |
| `access_token_ttl` | string (`\d+[smhd]`) | `ACCESS_TOKEN_TTL` | - |
Expand Down
Loading
Loading