diff --git a/src/content/docs/build/ecosystem.mdx b/src/content/docs/build/ecosystem.mdx index f3ae6fd..8b7f03f 100644 --- a/src/content/docs/build/ecosystem.mdx +++ b/src/content/docs/build/ecosystem.mdx @@ -165,7 +165,7 @@ rather than by assembling every piece manually. ## Compatibility Matrix -Versions and declared ranges of the latest release of each package as of **2026-10-29**: the npm +Versions and declared ranges of the latest release of each package as of **2026-11-01**: the npm `latest` tag for npm packages, and the latest GitHub Release for `seamless-auth-api` and `seamless-auth-admin-dashboard`. Ranges are read from the released `package.json`. Every package and the auth API require Node.js 22 or later (`engines.node` is `>=22`), except the messaging @@ -173,23 +173,24 @@ packages, which require Node.js 18 or later. | Package | Latest release | Declares on other Seamless packages | Other peer ranges | | --------------------------------- | -------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | -| `seamless-auth-api` | 0.20.0 | `@seamless-auth/types` ^0.33.0, `@seamless-auth/messaging`, `-aws`, `-twilio` ^0.2.0 | None | -| `@seamless-auth/core` | 0.22.0 | `@seamless-auth/types` ^0.33.0 | None | -| `@seamless-auth/express` | 0.22.0 | `@seamless-auth/core` ^0.22.0 | `express` >=5.0.0 | -| `@seamless-auth/fastify` | 0.13.0 | `@seamless-auth/core` ^0.22.0 | `fastify` >=5.0.0 | -| `@seamless-auth/nextjs` | 0.6.0 | `@seamless-auth/core` ^0.22.0, `@seamless-auth/types` ^0.33.0 | None | -| `@seamless-auth/client` | 0.8.0 | `@seamless-auth/types` ^0.33.0 | None | -| `@seamless-auth/react` | 0.19.0 | `@seamless-auth/client` ^0.8.0, `@seamless-auth/types` ^0.33.0 | `react` and `react-dom` 18 or 19, optional `react-router-dom` 6.4+ or 7.15.1+ | -| `@seamless-auth/angular` | 0.4.0 | `@seamless-auth/client` ^0.8.0 | `@angular/core`, `common`, `router` 20, 21, or 22, and `rxjs` 7 | -| `@seamless-auth/vue` | 0.3.0 | `@seamless-auth/client` ^0.8.0 | `vue` 3.5+, optional `vue-router` 4.4+ or 5 | -| `@seamless-auth/svelte` | 0.3.0 | `@seamless-auth/client` ^0.8.0 | `svelte` 5, optional `@sveltejs/kit` 2.26+ or 3 | -| `@seamless-auth/react-native` | 0.4.0 | `@seamless-auth/client` ^0.8.0, `@seamless-auth/types` ^0.33.0 | `react` 18 or 19 | -| `@seamless-auth/types` | 0.33.0 | None | None | -| `@seamless-auth/messaging` | 0.2.0 | None | None | -| `@seamless-auth/messaging-aws` | 0.2.0 | `@seamless-auth/messaging` ^0.2.0 | None | -| `@seamless-auth/messaging-twilio` | 0.2.0 | `@seamless-auth/messaging` ^0.2.0 | None | -| `seamless-cli` | 0.26.0 | `@seamless-auth/types` ^0.33.0 | None | -| `seamless-auth-admin-dashboard` | 0.11.0 | `@seamless-auth/react` ^0.19.0, `@seamless-auth/types` ^0.33.0 | None | +| `seamless-auth-api` | 0.21.0 | `@seamless-auth/types` ^0.34.0, `@seamless-auth/messaging`, `-aws`, `-twilio` ^0.2.0 | None | +| `@seamless-auth/oidc-provider` | 0.1.0 | `@seamless-auth/express` and `core` ^0.22.0, `@seamless-auth/types` ^0.34.0 | None | +| `@seamless-auth/core` | 0.23.0 | `@seamless-auth/types` ^0.34.0 | None | +| `@seamless-auth/express` | 0.23.0 | `@seamless-auth/core` ^0.23.0 | `express` >=5.0.0 | +| `@seamless-auth/fastify` | 0.14.0 | `@seamless-auth/core` ^0.23.0 | `fastify` >=5.0.0 | +| `@seamless-auth/nextjs` | 0.7.0 | `@seamless-auth/core` ^0.23.0, `@seamless-auth/types` ^0.34.0 | None | +| `@seamless-auth/client` | 0.8.2 | `@seamless-auth/types` ^0.34.0 | None | +| `@seamless-auth/react` | 0.19.2 | `@seamless-auth/client` ^0.8.2, `@seamless-auth/types` ^0.34.0 | `react` and `react-dom` 18 or 19, optional `react-router-dom` 6.4+ or 7.15.1+ | +| `@seamless-auth/angular` | 0.4.1 | `@seamless-auth/client` ^0.8.1 | `@angular/core`, `common`, `router` 20, 21, or 22, and `rxjs` 7 | +| `@seamless-auth/vue` | 0.3.1 | `@seamless-auth/client` ^0.8.1 | `vue` 3.5+, optional `vue-router` 4.4+ or 5 | +| `@seamless-auth/svelte` | 0.3.1 | `@seamless-auth/client` ^0.8.1 | `svelte` 5, optional `@sveltejs/kit` 2.26+ or 3 | +| `@seamless-auth/react-native` | 0.4.2 | `@seamless-auth/client` ^0.8.2, `@seamless-auth/types` ^0.34.0 | `react` 18 or 19 | +| `@seamless-auth/types` | 0.34.0 | None | None | +| `@seamless-auth/messaging` | 0.3.0 | `@seamless-auth/types` ^0.33.0 | None | +| `@seamless-auth/messaging-aws` | 0.3.0 | `@seamless-auth/messaging` ^0.3.0 | None | +| `@seamless-auth/messaging-twilio` | 0.3.0 | `@seamless-auth/messaging` ^0.3.0 | None | +| `seamless-cli` | 0.27.0 | `@seamless-auth/types` ^0.34.0 | None | +| `seamless-auth-admin-dashboard` | 0.12.0 | `@seamless-auth/react` ^0.19.0, `@seamless-auth/types` ^0.34.0 | None | How to read it: @@ -198,9 +199,10 @@ How to read it: bumped and released. - `@seamless-auth/express`, `fastify`, and `nextjs` declare `@seamless-auth/core` as `workspace:^`, which pnpm rewrites at publish to a caret on the core version in the same release - (`^0.22.0` today). -- Every package that depends on `@seamless-auth/types` declares ^0.33.0, so an app that installs - any mix of the SDKs and adapters resolves a single copy of it. + (`^0.23.0` today). +- Every SDK and adapter that depends on `@seamless-auth/types` declares ^0.34.0, so an app that + installs any mix of them resolves a single copy of it. The messaging packages still declare + ^0.33.0; only the auth API installs them. - The messaging packages are used by `seamless-auth-api` to deliver email and SMS. Your application does not install them. - The auth API exposes an HTTP contract, not a package range. No package declares a range on @@ -212,22 +214,22 @@ These are not npm packages, so they sit outside the table above and `npm run che declares no range on another Seamless package; it reads the auth API's adapter manifest at runtime instead. -| Adapter | Latest release | Registry | Needs | -| ------------------------------------ | -------------- | -------------------------------------------- | --------------------------------------------------- | -| `seamless-auth` (Python) | 0.3.0 | PyPI | Python 3.11+, FastAPI 0.115+ or Django 5.2+, auth API v0.18.0+ | -| `github.com/fells-code/seamless-auth-go` | v0.3.0 | Go module proxy (tag `v0.3.0`) | Go 1.22+, auth API v0.18.0+ | -| `seamless-auth` (Rust) | 0.3.0 | crates.io | Rust 1.88+, Axum 0.8, auth API v0.18.0+ | +| Adapter | Latest release | Registry | Needs | +| ---------------------------------------- | -------------- | ------------------------------ | -------------------------------------------------------------- | +| `seamless-auth` (Python) | 0.4.0 | PyPI | Python 3.11+, FastAPI 0.115+ or Django 5.2+, auth API v0.18.0+ | +| `github.com/fells-code/seamless-auth-go` | v0.4.0 | Go module proxy (tag `v0.4.0`) | Go 1.22+, auth API v0.18.0+ | +| `seamless-auth` (Rust) | 0.4.0 | crates.io | Rust 1.88+, Axum 0.8, auth API v0.18.0+ | ### What The CLI Scaffolds -`seamless-cli` 0.26.0 does not install the newest of everything. It pins the images and the +`seamless-cli` 0.27.0 does not install the newest of everything. It pins the images and the template tag it scaffolds, so a given CLI version always produces the same project: | What `seamless init` uses | Pinned to | Where it is set | | ------------------------- | -------------------------------------------------------------- | ------------------------------------------------------- | -| Auth API image | `ghcr.io/fells-code/seamless-auth-api:v0.20.0` | `seamless-cli` `src/core/images.ts` | -| Admin dashboard image | `ghcr.io/fells-code/seamless-auth-admin-dashboard:v0.11.0` | `seamless-cli` `src/core/images.ts` | -| Starter templates | `fells-code/seamless-templates` at `v0.21.0` | `seamless-cli` `src/core/images.ts` | +| Auth API image | `ghcr.io/fells-code/seamless-auth-api:v0.21.0` | `seamless-cli` `src/core/images.ts` | +| Admin dashboard image | `ghcr.io/fells-code/seamless-auth-admin-dashboard:v0.12.0` | `seamless-cli` `src/core/images.ts` | +| Starter templates | `fells-code/seamless-templates` at `v0.21.1` | `seamless-cli` `src/core/images.ts` | | Express API template | `@seamless-auth/express` ^0.22.0 | `templates/api/express/package.json` | | Fastify API template | `@seamless-auth/fastify` ^0.13.0 | `templates/api/fastify/package.json` | | Next.js template | `@seamless-auth/nextjs` ^0.6.0, `@seamless-auth/react` ^0.19.0 | `templates/fullstack/nextjs/package.json` | @@ -240,8 +242,11 @@ template tag it scaffolds, so a given CLI version always produces the same proje | Axum API template | `seamless-auth` 0.3 | `templates/api/axum/Cargo.toml` | | FastAPI API template | `seamless-auth[fastapi]>=0.3,<0.4` | `templates/api/fastapi/pyproject.toml` | -Template paths are inside `fells-code/seamless-templates` at `v0.21.0`. A scaffolded project can -move to newer SDKs by bumping the ranges in its own `package.json`. +Template paths are inside `fells-code/seamless-templates` at `v0.21.1`. Those templates still +declare the v0.20 adapters (`@seamless-auth/express` ^0.22.0, `fastify` ^0.13.0, `nextjs` ^0.6.0, +and the Go, Python and Rust adapters at 0.3), which work against auth API v0.21.0. A scaffolded +project can move to the v0.21 adapters by bumping the ranges in its own `package.json`, `go.mod`, +`Cargo.toml` or `pyproject.toml`. ### Keeping This Matrix Current diff --git a/src/content/docs/reference/release-v0-21.mdx b/src/content/docs/reference/release-v0-21.mdx new file mode 100644 index 0000000..60e3b84 --- /dev/null +++ b/src/content/docs/reference/release-v0-21.mdx @@ -0,0 +1,144 @@ +--- +title: 'v0.21 Release Notes' +description: 'What changed in Seamless Auth v0.21: an OpenID Provider for any OIDC app, verify-only resource servers, inbound OAuth from an issuer, application account notices, and upgrade steps.' +sidebar: + order: 8 +--- + +import { Aside } from '@astrojs/starlight/components'; + +v0.21 makes Seamless Auth an OpenID Provider. Any app that speaks OpenID Connect can sign users in +with Seamless passkeys through a new service, `seamless-auth-oidc-provider`, with no Seamless SDK. +It shipped as auth API 0.21.0 and OpenID Provider 0.1.0, with matching releases of the shared types, +server adapters, admin dashboard and CLI. 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. + + + +--- + +## OpenID Provider + +- **A separate edge service.** `seamless-auth-oidc-provider` is the public login edge in front of + the private API. It holds no database and no private keys: the API stores every provider record + and signs every token after checking its claims. It runs as an image + (`ghcr.io/fells-code/seamless-auth-oidc-provider`) or embeds in an Express app. See + [OpenID Provider](/build/openid-provider). +- **Locked to OAuth 2.1 and RFC 9700.** The code flow with `S256` PKCE, exact redirect matching + (RFC 8252 loopback ports for native apps), refresh rotation with reuse detection, `iss` on + authorization responses, and `private_key_jwt` for confidential clients. Shared secrets and a + per-client PKCE opt-out exist only for confidential apps that support nothing else, and only when + an admin turns them on. +- **Grants.** Authorization code, refresh token, client credentials, and the device authorization + grant (RFC 8628) for first-party CLIs and devices. Every device approval asks for a passkey again. +- **Tokens for your APIs.** Register a resource and its scopes, and an application asking with + `resource=` gets an RFC 9068 JWT access token whose `aud` is that API. Per-application token + lifetimes apply. +- **Hosted pages.** Login, consent, step-up, device verification and sign-out pages, branded from + the `hosted_ui` system config, served under a strict nonce CSP. +- **Step-up.** `acr_values`, `max_age` and `prompt=login` are honoured, and `acr` and `amr` reflect + how the user signed in, including a later step-up. +- **Sign-out.** RP-initiated logout at `/session/end`, and OpenID Back-Channel Logout tokens to + every app that registered a `backchannelLogoutUri` when the session behind a sign-in ends. +- **Introspection and revocation** (RFC 7662, RFC 7009). +- **Admin.** Applications and resources under `/admin/applications` and `/admin/resources` (admin + write and step-up, audited), the dashboard's Applications, Resources, OpenID Provider and Hosted + Page Branding screens, and `seamless clients`, `seamless resources` and + `seamless config hosted-ui` in the CLI. + +## Verify-Only Resource Servers + +APIs that receive the provider's access tokens check them without a cookie secret, service token or +auth routes. `createResourceServer({ issuer, audience })` in `@seamless-auth/express` and +`@seamless-auth/fastify`, and the matching verify-only mode in the Go, Python and Rust adapters, find +the keys through discovery and check `iss`, `aud`, the `at+jwt` header and the claims, with audience, +scope, role and step-up guards. + +## Inbound OAuth From An Issuer + +An inbound OAuth provider can be configured from its issuer alone. Endpoints you leave out are read +from the issuer's discovery document when the provider is used, cached for an hour, and held to the +same rules as typed ones. The dashboard's provider form has a "Discover from issuer" option, and the +CLI takes `seamless config oauth-providers add --issuer `. + +OAuth `state` replay records now live in the database, so a replayed `state` is refused by every +instance and callbacks no longer need sticky routing. + +## Account Notices From Applications + +`POST /applications/account-notices` lets a registered application tell one of its users something +on their verified email or phone without holding either. It takes a client credentials token with +scope `notices:send`, reaches only users who signed in to that application, and is rate limited per +application and per user. An admin turns it on per application. + +## Also In v0.21 + +- **Server adapters.** A proxied request that silently refreshed the session is served on the same + request, instead of failing once with `access session required`. A recovery session is rotated + right after it enrolls a passkey or authenticator app. +- **Go, Python and Rust adapters (0.4.0).** Check `allowedOrigins` alongside `Sec-Fetch-Site` and + verify the access token inside the cookie, matching the JavaScript adapters. +- **CLI (0.27.0).** `seamless migrate assess` writes a readiness report from the source alone, and + `seamless migrate auth0` and `migrate cognito` read the vendors' exports directly. `seamless init` + scaffolds templates v0.21.1, whose production images run as non-root on port 8080. + +--- + +## Upgrading + +Upgrade the auth API first, then the server adapters, the dashboard and the CLI. Clients need no +change. + +1. **Upgrade the auth API** to 0.21.0. It runs three additive migrations on start unless + `RUN_MIGRATIONS=false`: the provider tables, two session columns that record how the user signed + in, and the per-application PKCE and nonce settings. If you set `RUN_MIGRATIONS=false`, run them + first, because the server refuses to start while any migration is pending. The console at + `/console` is dashboard 0.12.0. +2. **Upgrade the server adapters**: `@seamless-auth/express` 0.23.0, `@seamless-auth/fastify` + 0.14.0, `@seamless-auth/nextjs` 0.7.0, or the Go, Python or Rust adapter 0.4.0. The dashboard's + OpenID Provider screens go through the adapter, so it must be one of these versions, or an adapter + that reads the live route manifest from API 0.21.0. +3. **Upgrade the dashboard** to 0.12.0 if you deploy it separately, and the **CLI** to 0.27.0. +4. **Do not set `OIDC_PROVIDER_ENABLED`** until the edge is ready. With it on, the API refuses to + start unless the issuer, `SEAMLESS_OIDC_SERVICE_TOKEN` and the `OIDC_JWKS_*` key set are all + valid. + +### Turning On The OpenID Provider + +Follow [Deploy The Edge](/build/openid-provider#deploy-the-edge). In order: + +1. **Pick the issuer hostname.** It must use `https`, differ from the API's `ISSUER`, and be your + `rpid` or a subdomain of it, for example `https://login.example.com`. +2. **Create the edge's secrets.** A new `SEAMLESS_OIDC_SERVICE_TOKEN`, set on both the API and the + edge, that differs from `SEAMLESS_SERVICE_TOKEN`. Never give the edge the adapters' token. A + provider key set for the API (`OIDC_JWKS_KEYS` and `OIDC_JWKS_ACTIVE_KID`) that shares no key + with `SEAMLESS_JWKS_*`. A `SEAMLESS_COOKIE_SECRET` and `OIDC_COOKIE_KEYS` for the edge. +3. **Deploy the API** with those secrets, and add the issuer origin to its `origins` config. +4. **Turn the provider on** from an admin session with a fresh step-up: the dashboard's System + Configuration, or `seamless config set oidc_issuer ` and then + `seamless config set oidc_provider_enabled true`. On a new instance, `OIDC_ISSUER` and + `OIDC_PROVIDER_ENABLED` seed both on first boot instead. +5. **Run the edge** (0.1.0, which needs auth API 0.21.0) behind TLS. Every cookie it sets is a + `__Host-` cookie, so it needs HTTPS in development too. Terminate TLS at a proxy, set + `TRUST_PROXY=true`, and keep the original `Host` header, or requests get + `421 misdirected_request`. The edge refuses to start while the provider is off or when the API + speaks a different `/oidc/*` contract version, so always deploy the API and the edge from the + same release. +6. **Check** `/.well-known/openid-configuration` and `/jwks` on the issuer, then + [register an application](/build/openid-provider#register-applications-and-apis) and sign in + once. + +## Not In v0.21 + +- Provider access tokens do not yet carry `roles`, `acr`, `amr` or `auth_time`, so the verify-only + role and step-up guards refuse them. Audience and scope checks work. +- An expired device code gets `invalid_grant` rather than `expired_token` + ([#542](https://github.com/fells-code/seamless-auth-api/issues/542)), and ending one application's + grant sends no back-channel logout ([#543](https://github.com/fells-code/seamless-auth-api/issues/543)). +- `seamless init` does not scaffold the OpenID Provider service yet. +- FIDO and OpenID certification are deferred to v1.0.