Auth UI: register, login, logout pages #67
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol#67
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The backend for register / login / logout / sessions / rate-limit / first-user-is-admin all landed under #11, but there is no UI for any of it — only API routes and
app/page.tsxdocumenting the endpoints. A self-hoster who isn't comfortable drivingcurlagainst/api/auth/registerhas no way to create their account.This ticket covers the minimum UI to make the existing backend usable by a human.
Scope
/registerpage (app/register/page.tsx) — email + password + confirm form. Submits to the existingPOST /api/auth/register. Surfaces the documented error codes as human copy:invalid_email,invalid_password,email_taken, and the 503policy_not_implementedcase (closed registration)./loginpage (app/login/page.tsx) — email + password form. Submits toPOST /api/auth/login. Surfaces wrong-credentials and rate-limited responses as actionable copy, not raw JSON.POSTs to/api/auth/logoutand redirects the browser to/login./loginand/registertolib/auth/public-routes.tswith PR-justified entries (matches the existing convention from #10 / ADR-0004).proxy.tsredirects unauthenticated browser navigation to a protected route →/login?next=<original>. Unauthenticated API requests keep returning 401 (the policy from #10 is unchanged for non-HTML).?next=if it's set and same-origin; otherwise to a default landing page./loginor/registeris redirected to the default landing, not shown the form again.app/page.tsx) — when there is no session, link to/loginand/register. When there is a session, link to the authenticated app shell.Acceptance criteria
/register, ends up signed in (the existing helper setsis_admin=1on the first user — no separate UI for that today), and lands on the post-registration destination./loginand land on the post-login destination./login. Hitting back on the browser does not re-authenticate./login?next=.... The same path requested as a JSON API still returns 401 with no body redirect.?next=is honoured; cross-origin or absolute external URLs are rejected.email_taken,invalid_password, andpolicy_not_implementedall render as human copy (not raw API JSON), and the form keeps the typed email so the user doesn't retype it.lib/auth/public-routes.tsfor each new public page, justified in the PR description.Out of scope
is_admin=1, but surfacing admin actions in the UI is a separate ticket once the admin role grants meaningful power.Composes with
register/login/logout/ sessions / rate-limit. This ticket is the UI half; the existing API contract is the integration surface.Part of epic #1.