feat(auth): passwordless email magic-link login#133
Open
mikedegeofroy wants to merge 1 commit into
Open
Conversation
Opt-in passwordless sign-in for the in-memory auth mode: the user enters their email on the login screen, the framework emails a single-use link, and following it establishes a session — no password typed. - Endpoints POST /api/auth/magic/request and GET /api/auth/magic/verify (auth-starter, new com.onec.auth.magic package); verify mints the session the same way /api/auth/login does, then redirects into the app. - JDBC-backed single-use token store (onec_auth_magic_link): only the token hash is persisted, consumption is atomic + expiry-checked, so links validate across every node of a horizontally-scaled deployment. - Pluggable SPIs (MagicLinkTokenStore / MagicLinkUserLookup / MagicLinkSender); default delivery emails the link via onec-mail-starter (compileOnly). - Opt-in per account via onec.auth.users[*].email; whole feature gated by onec.auth.magic-link.enabled (off by default). Request returns 202 whether or not the address is registered (no account enumeration). - AuthMethods.magicLinkEnabled (backward-compatible) drives the DivKit login card + a React onec-magic-link widget. - Order the auth auto-config after DataSource/mail auto-configs so the @ConditionalOnBean wiring sees those beans (fixes startup failure when the feature is enabled). - Docs synced (ARCHITECTURE, CONFIGURATION, both starter READMEs); 18 tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds opt-in passwordless "magic link" login for the in-memory auth mode. The user enters their email on the login screen, the framework emails a single-use link, and following it establishes a session — no password typed. It composes with password login (both render on the login card) and is inert in the OIDC / resource-server modes, where the IdP owns sign-in.
What's included
Backend (
onec-auth-starter, newcom.onec.auth.magicpackage)MagicLinkController— the two endpoints; verify saves theSecurityContextto the session exactly like/api/auth/login.MagicLinkService— 256-bitSecureRandomtokens; only the SHA-256 hash is persisted; no account enumeration (request always202).JdbcMagicLinkTokenStore—onec_auth_magic_linktable (JDBI +SqlDialect, mirroringMailOutbox); atomic, expiry-checked, single-use consumption so links validate across nodes.@ConditionalOnMissingBean):MagicLinkTokenStore,MagicLinkUserLookup,MagicLinkSender. Default delivery emails the link viaonec-mail-starter(addedcompileOnly, same optional-cross-starter pattern mail uses for print).Config
emailononec.auth.users[*]— opt-in per account (mirrors how an SSO backend keys a user by an external identity). Email-shaped usernames work without it.onec.auth.magic-link.*block:enabled(defaultfalse),token-validity(15m),base-url,redirect-path,subject.Login UI (
onec-ui-starter)AuthMethods.magicLinkEnabled(backward-compatible new field) →LoginDivBuilderrenders anonec-magic-linkDivKit block.onec-login-form, portaled on the login route.Auto-config ordering fix
before = SecurityAutoConfiguration, which ordered it ahead ofDataSourceAutoConfiguration/ the mail auto-config, so@ConditionalOnBean(DataSource/MailService)evaluated before those beans existed (the app failed to start with the feature on, even with a datasource). Now orderedafterthem.Requirements (fail-fast at startup if missing)
onec-mail-starterwith a configured provider (default sender), or a customMagicLinkSenderbean.DataSource(token persistence), or a customMagicLinkTokenStorebean.Test plan
MockMvc: 202 always, redirect + session, single-use), mail sender, and auto-config wiring + fail-fast guidance../gradlew checkgreen across all 12 modules; frontend type-checks (tsc -b) + builds + vitest pass.202) → following the link signed in asana@rentals.local(ROLE_CLEANER) → replaying the link was rejected to/login?error=link.docs/ARCHITECTURE.md,docs/CONFIGURATION.md(regenerated;checkConfigDocspasses),onec-auth-starter/README.md,onec-ui-starter/README.md.Notes
🤖 Generated with Claude Code