RCMV
InstallWeb ElementsLoginDatabase formDatabase API
Implementation tutorial

Add a login screen and authentication

A login feature that keeps HTTP handling, authentication decisions, credential access, and screen design in separate lanes.

Open the Login demo

Teach the state transition

  1. Signed out: the View owns the form and submits an intention.
  2. Checking: the Route hands POST to the Controller, which asks the authentication Model.
  3. Signed in: the Model returns a safe session result; the Controller selects ready; the View redirects or renders the authenticated state.

Passwords, provider tokens, and session storage belong behind the Model adapter—not in the Route, Controller, or View.

Route

src/routes/login.route.ts

GET renders the screen; POST submits credentials to the login Controller.

defineRoute({ method: 'POST', path: '/login',
  controller: authenticateUser, view: renderLogin })
Controller

src/controllers/login.controller.ts

Read the submitted intention, call the authentication Model, and choose success or invalid outcomes.

const form = await context.request.formData()
const result = await verifyUser(form)
return result.status === 'found'
  ? controller.ready(result.data)
  : controller.invalid({ email: 'Check your login' })
Model

src/models/auth.model.ts

Validate input, delegate credential verification to the auth adapter, and return only a safe session result.

const credentials = LoginInput.parse(Object.fromEntries(form))
const session = await auth.verify(credentials)
return session ? model.found(session) : model.missing()
View

src/views/login.view.ts

Own the form, accessible labels, validation messages, focus states, and successful redirect response.

return outcome.status === 'ready'
  ? redirect('/account', sessionCookie(outcome.data))
  : html(<LoginForm errors={outcome.fields} />)