Skip to content

feat(auth): email sign-in (link + code) and a factor-class 2FA gate at every sign-in path - #47

Merged
jsnyder10 merged 1 commit into
mainfrom
feat/auth-email-login
Sep 13, 2026
Merged

jsnyder10 merged 1 commit into
mainfrom
feat/auth-email-login

Conversation

@jsnyder10

Copy link
Copy Markdown
Contributor

Minor release for @factiii/auth (and @factiii/stack).

Email sign-in (features.emailLogin)

  • auth.emailLogin.request / verifyLink / verifyCode / peekLink. One attempt carries a hashed link token and an HMAC'd 6-digit code, consumed once atomically.
  • request answers the same for every address; per email+IP, IP and email rate limits; the send never changes the response.
  • The first verify of an unknown address creates an account with a VERIFIED email; a taken generated username is retried. An existing account whose email is not VERIFIED is refused.
  • app is a key into server config (own keys only); link hosts come only from config. peekLink returns a masked address for the confirm screen and spends nothing.
  • Password reset accepts the same app key.

One 2FA gate

  • requiresDeviceStep / runDeviceStep apply the factor-class rule to password login, email login, magic link and OAuth, with second-step guess limits and the credential spent before any push.
  • New hooks.beforeSessionMint runs at every mint site (password, email, magic link, OAuth before linking, passkey). DEACTIVATED and BANNED are refused everywhere.
  • verifyMagicLink is single-use atomically.

Rebased onto 0.20.6; the wildcard-safe lookups from #46 are unchanged in behaviour.

Independently security-reviewed; the findings are fixed in this branch. Tests: 280/280; check-types, lint and build clean. changeset status: minor for @factiii/auth and @factiii/stack.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H7frtoCH37E4RjrPC6zLPc

- emailLogin.request / verifyLink / verifyCode / peekLink behind
  features.emailLogin: one attempt carries a hashed link token and an HMAC'd
  6-digit code, consumed once atomically; uniform request response; per
  email+IP, IP and email rate limits; account created on first verify with a
  VERIFIED email and a retried generated username.
- requiresDeviceStep / runDeviceStep: one 2FA gate for password, email login,
  magic link and OAuth, with second-step guess limits.
- beforeSessionMint hook at every mint site; DEACTIVATED/BANNED refused
  everywhere, including magic link and passkey.
- verifyMagicLink is single-use atomically.
- Password reset accepts an app key.
- Wildcard-safe case-insensitive lookups (same fix as the 0.20.6 patch).
@jsnyder10
jsnyder10 merged commit d512720 into main Sep 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant