From f17bc016357fa3425ca31a6e4ebbd83ce2ce19c6 Mon Sep 17 00:00:00 2001 From: Brandon Corbett Date: Sun, 8 Nov 2026 07:19:40 -0500 Subject: [PATCH] docs: add v0.23 release notes, breaking changes and upgrade steps Refs fells-code/seamless-auth-api#561 --- src/content/docs/reference/release-v0-23.mdx | 186 +++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 src/content/docs/reference/release-v0-23.mdx diff --git a/src/content/docs/reference/release-v0-23.mdx b/src/content/docs/reference/release-v0-23.mdx new file mode 100644 index 0000000..d0fdcf7 --- /dev/null +++ b/src/content/docs/reference/release-v0-23.mdx @@ -0,0 +1,186 @@ +--- +title: 'v0.23 Release Notes' +description: 'What changed in Seamless Auth v0.23: roles and permissions in tokens, organization roles, custom claims, login hooks, signed webhooks, SIEM streaming, native app sign-in, security fixes, breaking changes and upgrade steps.' +sidebar: + order: 7 +--- + +import { Aside } from '@astrojs/starlight/components'; + +v0.23 makes Seamless Auth answer "what may this user do" as well as "who is this". Roles grant +permissions, tokens carry them per organization, every adapter can guard on them, and the auth +server calls out to your systems: signed webhooks, login hooks that can deny or add claims, static +custom claims, and audit streaming to a SIEM. It also finishes v0.21's native app work and the +fixes from its security review. + +It shipped as auth API 0.23.0 and OpenID Provider 0.4.0, with releases of the shared types (0.40.0), +server adapters (core and Express 0.26.0, Fastify 0.17.0, Next.js 0.10.0), the admin dashboard +(0.14.0) and the CLI (0.30.0). The Go, Python and Rust adapters' permission guards shipped in 0.6.0. +The versions that go together are in the +[Compatibility Matrix](/build/ecosystem#compatibility-matrix). Full details are in each package's +changelog and GitHub release. + + + +--- + +## Roles And Permissions + +- **Permissions in the access token.** An admin defines a permission catalogue and maps instance + roles to permissions. Access tokens carry a `permissions` claim, matched exactly with no + wildcards. See [How To Use Roles And Permissions](/build/roles-and-permissions). +- **Organization roles.** Organization roles are a catalogue now, seeded with `owner`, `admin` and + `member` plus every value memberships already hold. Inside an active organization, tokens carry + `org_id`, `org_roles` and `org_permissions`. Organization roles never appear in `roles`, so a + guard on `admin` does not pass for an organization admin. +- **Guards in every adapter.** `requirePermission` in `@seamless-auth/express`, and the matching + guards in Fastify, Next.js, Go, Python and Rust, check `permissions` and `org_permissions`. + `usePermissions()` in `@seamless-auth/react` 0.20.0 gates UI. Guards deny every request against an auth API + older than 0.23.0, since no token carries permissions there. +- **A token budget.** Permission and custom claims share 1 KiB + (`AUTHORIZATION_CLAIMS_BUDGET_BYTES`), which keeps an adapter's session cookie under the browser + limit. Over it, the token carries `permissions_omitted: true` and a guard reads + `GET /users/me/permissions` instead. +- **Admin tools.** The console's Roles page, and `seamless permissions` and `seamless roles` in + the CLI. + +## Extensibility + +- **Signed webhooks.** Endpoints under `/admin/webhooks`, signed with the Standard Webhooks scheme, + retried eight times over about 42 hours and then dead-lettered, with redelivery. Verify them with + `verifyWebhook` from `@seamless-auth/core/webhook`, or any Standard Webhooks library. See + [How To Receive Webhooks](/build/webhooks). +- **Login hooks.** A `post_login` hook runs once the factor is proven and may deny the sign-in. A + `pre_token` hook runs for a new session and on organization switch, and may add claims or deny. + Each hook fails open or closed, as you choose. Break-glass administrators and recovery sessions + never call a hook. +- **Custom claims.** Static claims per instance role, organization role or OpenID Provider client, + under `/admin/custom-claims`. See + [How To Use Login Hooks And Custom Claims](/build/login-hooks-custom-claims), which also maps + Auth0 Actions to them. +- **SIEM streaming.** Audit sinks under `/admin/audit-sinks` stream every audit event over + OTLP/HTTP, carrying the hash chain so it verifies from the SIEM's copy. Audit retention never + deletes an event a sink has yet to deliver. See + [How To Stream Audit Events To A SIEM](/operate/stream-audit-events-siem). +- **One set of reachability rules.** Webhooks, hooks and sinks refuse link-local, multicast and the + API's own host, never follow redirects, and in production refuse private addresses unless the + host is listed in `CALLOUT_PRIVATE_HOSTS`. +- **Admin tools.** The console groups Webhooks, Login hooks and Audit streaming under + Integrations. The CLI adds `seamless webhooks`, `seamless hooks`, `seamless claims` and + `seamless audit-sinks`. + + + +## OpenID Provider + +- **Roles, permissions and custom claims in provider tokens.** New scopes `permissions` and + `custom_claims` put them in ID tokens, `/userinfo` and RFC 9068 access tokens. The API signs only + values it computes again, so the edge cannot add or change one. +- **`org_id` is the active organization.** For provider tokens it now names the session's active + organization, not the user's oldest membership. +- **Key rotation without a restart.** The edge re-reads the signing keys every five minutes, and at + once when the API refuses a key as unknown. +- **`TRUST_PROXY` takes a hop count or addresses**, so the edge forwards the right client IP behind + more than one proxy. +- **Back-channel logout for one app.** An application whose grant ends while the first-party + session goes on now gets a logout token too. +- **Device codes.** A client polling an expired device code gets `expired_token`, as RFC 8628 says. +- **Hosted pages** meet WCAG 2.2 AA with the default palette, and errors the provider cannot send + back to the app render on them with your branding. + +## Native And Desktop Apps + +- **Session exchange.** A first-party native client that signs in through the OpenID Provider can + exchange the sign-in once for a first-party session of its own at `POST /sessions/exchange`, and + reach the admin API with it. A device-grant session needs a fresh step-up before admin and + organization routes, reads included. +- **CLI sign-in through the provider.** `seamless profile login` opens the system browser with a + loopback redirect, or uses the device grant with `--device`, which brings passkey sign-in to the + CLI. An instance can advertise the provider and the CLI's client in + `GET /system-config/public` (`oidc_cli_client_id`). +- **A confirmation for native clients.** The hosted pages ask the user to confirm "Continue to" the app for every native + client request, so a program listening on a loopback port cannot get a code without a click. + +## Security Fixes + +From the post-v0.21 security review: + +- A passkey's backup eligibility must match the one stored at registration, and hardware assurance + (`acr=phrh`, `amr=hwk`) comes from the registered credential. +- Application account notice text can no longer carry its own links, and the attribution is the + first line. +- `third_party_clients_enabled` gates existing third-party clients, not only new ones. +- External delivery needs a service token with subject `seamless-auth-external-delivery`. +- Every API response is `Cache-Control: no-store` unless its route sets its own caching. +- Provider requests go through the address guard in every mode. +- The per-user notice limit folds the user id to lower case before counting. +- The edge no longer leaves a grant behind when finishing a login fails, and `/session/end` no + longer signs a browser out of the hosted pages when there was no provider sign-in. + +Sharing rate limit counters across instances moved to v1.0 +([seamless-auth-api#581](https://github.com/fells-code/seamless-auth-api/issues/581)). Until then each +instance keeps its own counters, so several instances allow several times the budget, as +[Security](/understand/security) describes. + +--- + +## Breaking Changes + +Check each of these before you upgrade the auth API. + +| Change | Who it affects | What to do | +| ------ | -------------- | ---------- | +| Sign-in completion and `POST /organizations/:id/switch` can answer 403 `login_denied` or 503 `login_hook_unavailable` | Only instances that configure a login hook | Show the 403 `message` when present, and offer a retry for the 503 | +| A passkey whose backup eligibility changed since registration is refused with 401 | Rare. Usually a credential that moved between a device-bound and a synced store | The user signs in with another factor and registers the passkey again | +| `acr=phrh` and `amr=hwk` need attestation verified against the FIDO Metadata Service | Deployments on the default `none` attestation, and credentials registered before attestation was recorded | They now get `phr` and `swk`. Relax any guard that required `phrh`, or turn on attestation | +| `third_party_clients_enabled` off now stops existing third-party clients | Instances that turned the flag off after registering third-party clients | Turn the flag back on, or mark those applications first-party | +| External delivery needs the `seamless-auth-external-delivery` service token subject | Only callers that mint their own service token for external delivery | Set `sub` to `seamless-auth-external-delivery`. Current adapters already do | +| Account notice `text` with a URL, domain or email address is refused with 400 | Applications calling `POST /applications/account-notices` | Put the link in `actionUrl`. Adapters rendering notices receive the attribution as the first line | +| Assigning an organization role outside the catalogue answers 400 | Admin tools that assign free-form roles | Create the role first. Existing memberships are seeded into the catalogue | +| `PATCH /organizations/:id/members/:userId` needs step-up, and only an owner or an instance `admin:write` can grant or remove `owner` | Organization admins | Organization admins step up first. They can no longer make themselves owner | +| Provider tokens' `org_id` is the active organization | Provider clients that read `org_id` | Read it as the active organization, or switch organization first | +| Applications with a `backchannel_logout_uri` get logout tokens for one-app logouts too | Provider clients with back-channel logout | Treat it like a full logout for that `sid` | + +--- + +## Upgrading + +Upgrade the auth API first, then the OpenID Provider, the server adapters, the +dashboard and the CLI. Clients need no change. + +1. **Upgrade the auth API** to 0.23.0. It runs eight additive migrations on start unless + `RUN_MIGRATIONS=false`: application links, session exchange, permissions, organization roles, + webhooks, audit sinks, login hooks and custom claims. If you set `RUN_MIGRATIONS=false`, run them + first, because the server refuses to start while any migration is pending. No setting is + required to upgrade. +2. **Set `CALLOUT_SECRET_ENCRYPTION_KEY`** before you create a webhook or a login hook in + production, which requires it once one exists. It encrypts their stored signing secrets. Credentials for audit sinks + are env vars ending `_AUDIT_SINK_SECRET`, named by the sink and never stored. +3. **Upgrade the OpenID Provider** to 0.4.0, if you run it. It speaks the same `/oidc/*` contract as + API 0.22.0 and 0.23.0, but needs 0.23.0 for the new scopes. +4. **Upgrade the server adapters**: `@seamless-auth/express` 0.26.0, `@seamless-auth/fastify` + 0.17.0, `@seamless-auth/nextjs` 0.10.0, or the Go, Python or Rust adapter 0.6.0. +5. **Upgrade the dashboard** to 0.14.0 if you deploy it separately, and the **CLI** to 0.30.0. +6. **Define permissions and map roles** before you add guards. A guard on a permission no role + grants refuses everyone. + +## Not In v0.23 + +- Syslog audit sinks, in 0.23.1 + ([seamless-auth-api#586](https://github.com/fells-code/seamless-auth-api/issues/586)). +- Rate limit counters are per instance + ([seamless-auth-api#581](https://github.com/fells-code/seamless-auth-api/issues/581)). +- The server adapter's cookie holds the token budget at 1 KiB. A larger budget waits on the cookie + change in [seamless-auth-server#278](https://github.com/fells-code/seamless-auth-server/issues/278), + planned for v1.0. +- OpenID certification is not done. The provider passes the OpenID conformance suite in CI, and + the certification fee waiver is pending + ([seamless-auth-api#412](https://github.com/fells-code/seamless-auth-api/issues/412)).