Spacerr
  • Features
  • Pricing
  • FAQ
  • Docs
Get Access
Spacerr
  • Introduction
  • Features
  • Tech Stack
  • Setup
  • Configuration
  • Agents
  • Database
  • Jobs
    • Overview
    • Sign in and sign up
    • Passkeys and 2FA
  • Admin
  • Settings
  • Billing
  • Storage
  • Email
  • Support
  • Localization
  • SEO
  • Analytics
  • UI And Navigation
  • Deploying To Production
  • Testing And QA
  • Troubleshooting

Search documentation

Search documentation pages.

Documentation/Sign In And Sign Up

Sign In And Sign Up

The auth UI is owned by src/features/auth/components. Route files stay thin and render feature components for sign in, sign up, forgot password, and reset password.

Route Pages

Auth uses individual route pages for each user facing flow.

txt
export default async function SignInPage({ searchParams }: SignInPageProps) {
  return (
    <Suspense fallback={<Spinner centered />}>
      <SignInComponent searchParams={searchParams} />
    </Suspense>
  )
}

async function SignInComponent({ searchParams }: SignInPageProps) {
  const resolvedSearchParams = await searchParams
  const user = await getSessionUser()

  if (user) {
    const safeNext = getSafeNextFromSearchParamsRecord(resolvedSearchParams)
    redirect(safeNext ?? WebRoutes.dashboard.path)
  }

  return <Auth activeTab="sign-in" />
}

The public routes are:

  • /sign-in
  • /sign-up
  • /forgot-password
  • /reset-password

Each route owns its own metadata, redirect behavior, and canonical URL. The shared Auth shell still receives an internal activeTab value so the same feature component can render the right form and preserve callback URLs.

Sign In Methods

Sign in supports:

  • Google OAuth.
  • Magic link by email.
  • Email and password.
  • Passkey.

The sign in form lives in src/features/auth/components/sign-in/sign-in-form.tsx.

typescript
const result = await signInWithEmailAndPasswordAction({
  email,
  password,
  callbackURL: buildCallbackUrl(),
  embedded: true,
})

If the account has two factor authentication enabled, the server action returns a two factor required response. The UI then lets Better Auth continue the verification flow.

Sign Up Methods

Sign up supports:

  • Google OAuth.
  • Magic link by email.
  • Email and password.

The sign up form lives in src/features/auth/components/sign-up/sign-up-form.tsx. Email and password signup creates the user, uses the configured callback URL, and signs the user into the dashboard when the flow succeeds.

typescript
await auth.api.signUpEmail({
  body: {
    name: "User",
    email,
    password,
    callbackURL: callbackURL ?? ApiRoutes.authSignedIn,
  },
  headers: await headers(),
})

Better Auth also creates the Stripe customer on signup through the Stripe plugin configured in auth.ts.

Google OAuth

Google OAuth is started by signInWithGoogleAction.

typescript
await auth.api.signInSocial({
  body: {
    provider: "google",
    callbackURL,
  },
  headers: await headers(),
})

The setup guide covers the Google Cloud credentials. The important rule is that the authorized redirect URI must match the Better Auth callback route for the current domain.

txt
http://localhost:3000/api/auth/callback/google
https://your-domain.com/api/auth/callback/google

If the auth base path changes, update the redirect URI in Google Cloud as well.

Magic Links

Magic link sign in is handled by the Better Auth magic link plugin.

typescript
magicLink({
  sendMagicLink: async ({ email, url }) => {
    await sendMagicLinkEmail({
      to: email,
      url,
    })
  },
})

The UI shows a check your email state after the link is sent. The email content is sent through the email feature, so template copy belongs in the email layer.

Password Reset

Password reset is enabled in auth.ts and uses the email feature to send reset links.

typescript
resetPassword: {
  enabled: true,
}

The request form lives in src/features/auth/components/forgot-password/forgot-password-form.tsx. The reset form lives in src/features/auth/components/reset-password/reset-password-form.tsx.

Validation lives in src/features/auth/lib/auth.schema.ts.

typescript
export const resetPasswordSchema = z
  .object({
    newPassword: passwordSchema,
    confirmPassword: passwordSchema,
  })
  .refine((data) => data.newPassword === data.confirmPassword, {
    path: ["confirmPassword"],
    message: "Passwords do not match",
  })

Account Reactivation

Users with a deactivated account can reactivate during sign in after their credentials are verified. The server side logic lives in src/features/auth/lib/auth.repository.ts, and the confirmation UI lives in src/features/auth/components/sign-in/sign-in-reactivate-dialog.tsx.

This keeps deactivation reversible without exposing account state changes to unauthenticated users.

Authentication

Learn how authentication is structured in Spacerr.

Passkeys And 2FA

Learn how passkeys, two factor authentication, backup codes, and account security settings work.

On this page
Route PagesSign In MethodsSign Up MethodsGoogle OAuthMagic LinksPassword ResetAccount Reactivation