v0.2.0 — 2FA, Apple + Facebook, richer SCIM, RFC-compliance hardening
go-auth-x v0.2.0
A big release: two-factor auth, two more social providers, a much richer SCIM server, and a full RFC-compliance hardening pass. All additive at the public-API level (no removals/renames); a few security-hardening behavior changes are noted below.
✨ Highlights
Two-factor auth (2FA) — no third-party dependency
- TOTP (RFC 4226/6238) implemented in the standard library only (verified against the published RFC test vectors) — the frontend renders the QR from an
otpauth://URI. - Recovery codes — single-use, sha256-at-rest.
- Login enforcement — when 2FA is on, the first factor sets a short-lived signed
2fa_pendingcookie instead of the session;POST /auth/2fa/verify(a TOTP or recovery code) finishes it. Replay-guarded and rate-limited. - Passkey as a second factor — complete the second step with a registered passkey (
/auth/2fa/webauthn/begin+/finish) instead of a code. - Step-up / re-auth —
RequireStepUpHTTP(maxAge)gates sensitive routes;POST /auth/reauth(password or a 2FA code) sets a short-lived step-up cookie. - Wire the optional
TwoFactorStore(gormstore + memory reference impls) withSetTwoFactorStore.
Social login: Apple + Facebook
- Sign in with Apple — the library signs the ES256 client-secret JWT from your
.p8and handles Apple'sform_postcallback (SameSite=Noneflow cookie; HTTPS required). - Facebook — Graph API
/mewith anappsecret_proof. - Both follow the same verified-email account-linking rule as Google/GitHub.
SCIM 2.0 — much more conformant
- Filters:
eq/ne/co/sw/ew/gt/ge/lt/le/prwithand/or/not, parentheses, and valuePath (emails[type eq "work"]). - Sorting (
sortBy/sortOrder), strong ETags (If-Match/If-None-Match),Location/meta.location(setSetBaseURL),uniquenessscimType, PATCHnoTarget/op validation, and the/Bulkendpoint.
🔒 Security / compliance (RFC audit)
An audit against ~27 RFCs/specs found and this release fixes 11 MUST-level gaps — all in caller-owned wiring, not the delegated crypto:
- JWT token-audience segregation — session / oauth-flow / 2fa-pending / webauthn tokens now carry a distinct validated
aud, closing a path where a2fa_pendingtoken could be replayed as a session (2FA bypass). (RFC 7519) - WebAuthn UserVerification is now Required — a passwordless passkey is a real multi-factor credential, not a bare possession factor. (WebAuthn L2)
randTokenfails closed on acrypto/randerror instead of emitting a guessable state/CSRF/API-key token. (RFC 6749)- TOTP past-leaning validation window + rate-limited verify. (RFC 4226/6238)
- LDAP StartTLS sets
ServerNameand refuses a cleartext bind. (RFC 4513) - OIDC validates
azp. (OIDC Core) - Bearer admin guard returns
401 + WWW-Authenticate/403 insufficient_scope. (RFC 6750) - SCIM strong ETags for If-Match,
Location/uniqueness/PATCH validation. (RFC 7644 / 9110)
Upgrade
go get github.com/alex-savin/go-auth-x@v0.2.0Public API is source-compatible with v0.1.x. Behavior changes to be aware of: WebAuthn logins now require user verification (a UV-capable authenticator); the admin Bearer guard returns 401 (not 403) for an invalid/missing key; SCIM ETags are now strong (no W/ prefix).
Full changelog: https://github.com/alex-savin/go-auth-x/blob/main/CHANGELOG.md