ZigBase 0.5.0
·
1111 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Removed
- BREAKING: legacy OAuth2 endpoints removed —
GET .../oauth2-providers,POST .../oauth2-init, andPOST .../auth-with-oauth2no longer exist. OAuth2 is now exclusively the contract method:POST .../auth/oauth2/initiate,POST .../auth/oauth2/complete, andGET .../auth/oauth2/providers(discovery).
Added
- OAuth2 as a first-class
AuthMethod— exclusively at the contract endpointsPOST /auth/oauth2/initiate,POST /auth/oauth2/complete, andGET /auth/oauth2/providers(discovery); all paths share one implementation and the singleonAuthsession seam. See docs/api.md for request/response shapes. - Pluggable auth-method system — the
AuthMethodcontract (initiate/complete+AuthCtxblessed helpers +Resolution) lets the framework own session issuance while methods plug in verification logic. Built-ins implement the same contract with no privileged path. - Per-collection
.auth.methodsconfig — enable and configure built-in methods per auth collection:password(backward-compat default when.methodsis absent),magic_link(TTL, auto-create flag),otp(code length, TTL),webauthn(rp_id, rp_name, origin, credentials_collection). Each method has arate_limitknob (.default|.off|.{ .custom = .{ .max, .window_s } }). - App-level
.auth_methods— register customAuthMethodplugin TYPES at comptime (same pattern as.storage/.mailer); a type missingcreate/method/deinitis a compile error. - Auto-mounted auth endpoints — for every enabled method, the framework auto-mounts
POST /api/collections/:col/auth/:method/initiateand.../complete; the dispatch enforces enablement (404 for disabled/unknown methods) and default rate-limits. magic_linkbuilt-in — enumeration-safeinitiate(always 204), single-use link token emailed via the configured mailer,completeverifies+consumes and mints the session.otpbuilt-in — enumeration-safeinitiateemails a 6-digit code stored in theChallengeStore,completeverifies the code.webauthnbuilt-in — passkey login via the two-phase contract (initiate returnsPublicKeyCredentialRequestOptions; complete verifies the signed assertion). Passkey registration via two authed endpoints (register/begin/register/finish). ES256 (P-256, COSE -7) and Ed25519 (COSE -8) supported; attestationfmt:"none"(v1); signCount clone detection (fail-closed); credentials stored in_webauthnCredentials.ChallengeStore(_authChallenges) — TTL'd, GC'd single-use server-side challenge storage used byotpandwebauthn, and accessible to custom plugins viaAuthCtx.challengeStore().onAuthmethod tagging extended —AuthEvent.methodis an enum:.password,.oauth2,.magic_link,.otp,.webauthn, or.customfor custom plugins.- RPC client generation for auth endpoints — the generated TypeScript client exposes non-password auth-method endpoints under an
authsurface (initiate/complete stubs, currently untyped). zigbase.authconsumer surface for custom auth flows —issueSession(andRouteEvent.issueSession), single-use magic-link tokens (mintLinkToken/verifyLinkToken/consumeLinkToken),deliverAuthMail, andrateLimit. All session minting now funnels through one seam that always firesonAuth.
Security
- OAuth2 server-side CSRF
stateis now ON by default (ZIGBASE_OAUTH_STATE_SERVERdefaults totrue). Theinitiateendpoint issues astatevalue andcompleterequires and consumes it before contacting the provider. Behavior change: OAuth2 clients must use theinitiate→completeflow; barecompletecalls without a validstateare rejected with400. SetZIGBASE_OAUTH_STATE_SERVER=falseto restore the previous client-driven mode. - New
require_verifiedper-collection auth option (defaultfalse). Whentrue, any login attempt for an unverified record is rejected with403. This gate applies to all methods — including WebAuthn/passkey and OAuth2 accounts whose provider email was unverified (those are createdverified=false). Enabling it will lock out such users until they complete email verification. - OAuth2 no longer claims unverified provider emails — when a provider does not mark the email as verified, the new account is created with
verified=falseand theemailfield is left unpopulated. This prevents email-squatting via an OAuth2 provider that does not verify addresses. - WebAuthn credential binding — a passkey is now bound to the collection it was registered on; presenting it on a different collection returns
401. - WebAuthn
require_uvoption (defaultfalse). Whentrue, the server rejects assertions that do not set the user-verification bit (UV=1), requiring biometrics or PIN at the authenticator. - WebAuthn COSE key curve validation — ES256 credentials must use the P-256 curve; EdDSA credentials must use Ed25519. A mismatched algorithm/curve is rejected.
Performance
- Auth I/O off the write lock.
otpandmagic_linkrelease the DB connection before the SMTP send. WebAuthn signature verification runs before acquiring the write lock (only the signCount update and challenge consume hold it).oauth2Providersuses a reader connection. The authenticated-request fast path no longer does a redundant collection lookup. No auth method holds the single writer across blocking I/O or CPU-heavy verification.
Changed
- Auth methods now manage their own DB connections — each method holds one connection across its work; OAuth2
completereleases the writer during the provider HTTP exchange (no write-throughput stall); passwordcompleteuses a reader (argon2 is read-only). Neither method blocks writes during I/O. - Session issuance (password, refresh, OAuth2) routes through a single
issueSession+emitAuthseam — custom routes can no longer mint a session that
skips theonAuthhook.