Auth Pages
Eight pages for the whole credential lifecycle
Authentication on the backend gives you the routes; these eight pages give you the screens, so you almost never hand-build an auth form again. Each page takes the matching generated action as a prop, owns its form, validation, captcha and multi-step state machine, and calls your callbacks at the right moments. You provide routing and branding.
They cover the entire journey: LoginPage and RegisterPage for entry, ForgotPasswordPage → ResetPasswordPage for recovery, SetPasswordPage for invites and magic-link landings, ChangePasswordPage for signed-in users, and VerifyEmailPage / MagicLinkVerifyPage for the links your emails send. Password rules are enforced with a consistent live strength meter across the password pages — though not by a single shared engine: RegisterPage uses its own PasswordPolicyConfig type while ResetPasswordPage/SetPasswordPage share a separate PasswordPolicy type (with preventCommonPasswords / preventUserInfoInPassword), and ChangePasswordPage applies a fixed 8-char minimum rather than a configurable policy.
Everything shares the library contract — a useXStore for state and lifecycle callbacks (LoginPage and RegisterPage accept a variant prop, though it is not yet wired to any layout change). Wire the action, set a couple of links, and the page is production-ready. (Auth pages take no theme prop, and — apart from MagicLinkVerifyPage's magicLinkVerifyPageTheme constant — nucleus-core/fe does NOT export per-page theme constants or extend<Page>Theme helpers for them; deeper restyling is via className and your own CSS. Beyond the eight page components and their per-page useXStore hooks, the additional auth-related exports from fe are magicLinkVerifyPageTheme, DEFAULT_PASSWORD_POLICY, and PasswordStrengthIndicator.)
Wiring an auth page#
The minimum is one action; everything else has a sensible default. Pages never navigate for you — they fire onSuccess so you stay in control of routing.
1import { LoginPage } from "nucleus-core/fe";2import { useApiActions } from "@/lib/api";3 4export default function Login() {5 const actions = useApiActions();6 return (7 <LoginPage8 variant="default" // accepted but not yet implemented (no-op)9 loginAction={actions.LOGIN}10 meAction={actions.ME}11 logoutAction={actions.LOGOUT}12 captchaGenerateAction={actions.CAPTCHA_GENERATE}13 showRememberMe14 showForgotPassword15 forgotPasswordHref="/forgot-password"16 signUpHref="/register"17 onSuccess={() => router.push("/app")}18 />19 );20}variant'default' | 'minimal' | 'split'OptionalAccepted on LoginPage and RegisterPage only (the other six auth pages take no variant), but currently a no-op: both components destructure it as an intentionally-unused prop and never branch on it, so 'minimal' and 'split' render the identical default card layout — the layout-shape names are not yet implemented.
'default'logo / title / subtitleReactNode / stringOptionalBranding slots. Login also takes loggedInTitle for the already-signed-in state (loggedInSubtitle is accepted by the LoginPage type but is currently a no-op — the signed-in subtitle is hard-coded to `Signed in as <email>`, mirroring the unwired variant prop above).
showBackground / classNamestylingOptionalToggle the built-in AbstractAnimatedBackground and add classes. showBackground / AbstractAnimatedBackground applies to the six card-style pages (Login, Register, Forgot/Reset/Set/ChangePassword) — VerifyEmailPage and MagicLinkVerifyPage declare no showBackground prop and render no background. Auth pages take no theme prop and export no per-page theme constant or extend<Page>Theme helper (MagicLinkVerifyPage's magicLinkVerifyPageTheme is the sole exception); deeper restyling is via className and your own CSS.
onSuccess / onLogout / onForgotPassword / onSignUp() => voidOptionalLifecycle callbacks. The page does the API work and calls these so you own navigation. Link variants (forgotPasswordHref, signUpHref) are provided as an alternative to callbacks.
LoginPage#
Email/username + password sign-in with optional captcha and remember-me. Reads the LOGIN action and, optionally, ME (to render a signed-in state) and LOGOUT.
loginActionLoginActionOptionalRequired. payload is { email, password, rememberMe?, captchaId?, captchaAnswer? }; on success the cookies are set by the client and onSuccess fires.
meAction / logoutActionMeAction / LogoutActionOptionalSupply ME to let the page detect an existing session and show the logged-in panel; LOGOUT powers the sign-out button there.
captchaGenerateAction + config.login.captchaCaptchaAction + CaptchaConfigOptionalEnables the Captcha challenge on the form. The page requests a challenge and submits captchaId/captchaAnswer with the login payload. (config.login — the LoginFeatureConfig — carries only captcha and redirectUrl; redirectUrl is accepted by the type but currently inert — no LoginPage component reads it, the page fires onSuccess and never navigates — mirroring the unwired variant / loggedInSubtitle props above.)
showRememberMe / showForgotPassword / showSignUpbooleanOptionalToggle the secondary controls; pair with forgotPasswordHref / signUpHref or the onForgotPassword / onSignUp callbacks.
RegisterPage#
Sign-up with a live password-strength meter, optional name fields, profile creation and terms gating. Driven by the REGISTER action and a config.passwordPolicy.
registerActionRegisterActionOptionalRequired. payload is { email, password, firstName?, lastName?, createProfile? }.
config.passwordPolicyPasswordPolicyConfigOptionalRules enforced live, with the strength meter. Note: on RegisterPage only minLength and the four require* flags actually take effect — maxLength, specialChars and showStrengthIndicator are accepted by the PasswordPolicyConfig type but are NOT wired on this page (there is no max-length check in the form's validation, the special-character set is a fixed regex in the store rather than driven by specialChars, and the strength meter always renders whenever a password has been typed). Those three ARE honored instead on ResetPasswordPage / SetPasswordPage, which use the separate PasswordPolicy type.
minLengthnumberOptionalMinimum password length (defaults to 8). Enforced live as the user types.
maxLengthnumberOptionalMaximum length. Accepted by the type but inert on RegisterPage — the form runs no max-length check. Honored on ResetPasswordPage / SetPasswordPage.
requireUppercase / requireLowercase / requireNumber / requireSpecialCharbooleanOptionalCharacter-class requirements checked as the user types.
specialCharsstringOptionalThe set of characters that count as 'special' for the rule above. Inert on RegisterPage — special-char detection is a fixed regex in the RegisterPage store, not driven by this field. Honored on ResetPasswordPage / SetPasswordPage.
showStrengthIndicatorbooleanOptionalRender the PasswordStrengthIndicator (score + per-rule checklist); exported standalone too. Inert on RegisterPage — the indicator always renders whenever a password has been typed, regardless of this flag. Honored on ResetPasswordPage / SetPasswordPage.
config.registerRegisterFeatureConfigOptionalFeature toggles: showFirstName, showLastName, createProfileOnRegister, and termsUrl / privacyUrl for the consent links. (showTerms is a top-level RegisterPage prop — not a config.register field — and requires acceptance.)
Password recovery & set#
The reset journey and the invite/magic-link landing. ResetPasswordPage and SetPasswordPage accept the same PasswordPolicy type — but only its minLength / maxLength / require* / specialChars fields are actually enforced by their forms; preventCommonPasswords / preventUserInfoInPassword are declared on the type (and default to on) yet are inert client-side, so any enforcement would have to be server-side. ForgotPasswordPage collects only an email, and ChangePasswordPage applies a fixed minimum-length + strength check.
ForgotPasswordPageForgotPasswordActionOptionalCollects the email and triggers the reset mail. Steps: request → success. Pair with backToLoginHref.
ResetPasswordPageResetPasswordActionOptionalThe landing for the emailed reset token — takes a new password (policy-checked), submitted together with the token, and confirms. Steps: form → success. (Unlike SetPasswordPage/VerifyEmailPage there is no separate verifying/error step — the token isn't pre-validated.)
SetPasswordPagemagicLinkVerifyAction + passwordSetAction / passwordChangeActionOptionalDual-purpose: accepting an invite (isInvite) to set an initial password, or landing from a magic link. It verifies the token then sets the password. Takes the token as a prop and a passwordPolicy.
ChangePasswordPageChangePasswordActionOptionalFor an already-signed-in user — current + new + confirm, with a fixed 8-char minimum + strength check (no configurable passwordPolicy prop). No token needed.
DEFAULT_PASSWORD_POLICYRequired<PasswordPolicy>OptionalThe exported baseline used when you don't pass one: minLength 8, maxLength 128, upper+lower+number required, special optional, preventCommonPasswords and preventUserInfoInPassword on (but inert — no form enforces these two; any enforcement would be server-side), strength indicator shown.
Email verification & magic link#
The pages your transactional emails point at. Both consume a token from the URL and call their verify action: VerifyEmailPage runs a verifying → success → error machine, while MagicLinkVerifyPage prepends an optional 'ready' (click-to-confirm) step ahead of those same three. Minimal wiring, mostly presentation — and both auto-redirect on success after a configurable redirectDelay (3000ms VerifyEmail / 2000ms MagicLink).
VerifyEmailPageVerifyEmailAction + ResendVerificationActionOptionalConfirms a new account's email from the token, and offers a resend whenever verification fails (an expired or otherwise-invalid token — the resend lives in the generic error step). Steps: verifying → success → error, auto-redirecting on success after redirectDelay (default 3000ms) by firing onSuccess (falling back to onBackToLogin). The resend form is toggleable via showResendForm (defaults to true) and only renders when a resendVerificationAction is also supplied — the component guards on `showResendForm && resendVerificationAction`; an optional email prop prefills that resend field.
MagicLinkVerifyPageMagicLinkVerifyActionOptionalCompletes a passwordless sign-in from a magic-link token, then hands off via onSuccess after redirectDelay (default 2000ms), while onError fires on any verification-failure path (empty/non-success response or a thrown error). By default it auto-verifies on mount (step machine verifying → success → error); set requireConfirmation (default false) to prepend a 'ready' step that gates verification behind a 'Verify & Sign In' button — handy to keep email-scanner prefetches from silently consuming the one-time token. A texts prop overrides every label (confirmTitle / confirmSubtitle / confirmButton, verifyingTitle / verifyingSubtitle, successTitle / successSubtitle, errorTitle, backToLogin). Exports the magicLinkVerifyPageTheme constant — the sole per-page theme export among the auth pages — though like every auth page it has no extend* helper (fe's extend<Page>Theme exports belong to non-auth pages such as AuthorizationPage / VerificationFlowPage).
Related sections