Make sign-in predictable.

Authentication is a flow, not a button: sessions, protected routes, email verification, Google sign-in, password resets and signed-out states.

Forms and Auth · 8 min read · Updated 2026-06-06

Define the states

This comes down to a handful of concrete details. Work through the list below and flag the ones you have not covered yet.

  • Signed out: show sign-in and create-account actions.
  • Submitting: prevent duplicate credentials requests.
  • Signed in but unverified: explain the verification step.
  • Session loading: avoid redirecting before the session is hydrated.
  • Expired session: return the user to a safe sign-in route.

OAuth redirect rules

Send OAuth callbacks to a same-origin callback route, not directly to a protected screen. Store the intended destination separately and navigate there after the session is available. This avoids losing the session or redirecting before the app knows who is signed in.

  1. Configure the provider and exact redirect origins.
  2. Start the OAuth flow from a clear user action.
  3. Handle the callback and wait for session hydration.
  4. Show a useful error for cancelled or rejected consent.
  5. Test refresh, sign-out and a second account.
Never decide admin access from local storage, a hidden field or a client-only boolean. Authorize privileged operations on the backend.

Password reset

Use a dedicated reset route, accept the token only through the auth flow and show a confirmation after the new password is saved. Do not reveal whether an email address exists in a way that enables account enumeration.

Rollout checklist

Use the list below as a working checklist. Each item is something you can verify or action directly on your own site.

  • Test sign-up, sign-in, sign-out and refresh in a private browser window with no prior session.
  • Confirm the redirect origins registered with the provider match the deployed domain exactly, including protocol and any preview subdomain.
  • Confirm an unverified account cannot reach protected content by URL alone.
  • Confirm a password reset link expires and cannot be reused after the password changes.
  • Confirm signing out clears the session everywhere the app checks for it, not just in one component.

Diagnosing a broken sign-in

Here are the key things to get right. None of them are complicated on their own, but skipping one tends to undermine the rest.

  • Blank screen after OAuth redirect: the callback route is missing or the app is redirecting before the session resolves.
  • Signed in on refresh but treated as signed out immediately: session hydration is being read before it completes.
  • Google sign-in works locally but fails in production: the production redirect origin is not registered with the provider.
  • Reset link opens the app signed out with no error: the token is being dropped before the auth flow reads it.

Frequently asked questions

Questions

This usually happens when a protected route checks the session before it has finished hydrating from storage. Wait for the session-loading state to resolve before deciding whether to redirect.

The OAuth provider only allows redirects to origins you have explicitly registered. Add the exact production origin, including subdomain, to the provider's allowed redirect list.

Never on the client alone. Store the role server-side and check it in database policy or a backend function for any privileged action, treating client-side role checks as a display convenience only.

Want your app built properly?

We take Lovable prototypes to production: secure data, real auth and a clean deploy.