Authentication Pages
The authentication flow consists of three pages: login, OTP verification, and onboarding.
Login Page
Route: /login
File: app/login/page.tsx
The login page presents a centered card with an email input field. When the user submits their email:
- Calls
POST /api/auth/otp/sendwith the email - On success, navigates to
/login/verify?email=<email> - On failure, shows a toast error
UI Elements:
AuthPageShellwrapper (centered card layout with theme toggle)- Email input with validation
- Submit button with loading state
- Uses Preact signals for state
OTP Verification Page
Route: /login/verify
File: app/login/verify/page.tsx
The verification page shows an 8-digit OTP input. The email is read from the URL query parameter.
Flow:
- If no
emailquery param → redirect back to/login - User enters the 8-digit code from their email
- Calls
POST /api/auth/otp/verifywith email + token - On success:
- Stores access and refresh tokens via
setTokens() - If user has no first name → redirect to
/onboard - Otherwise → redirect to
/dashboard
- Stores access and refresh tokens via
- On failure, shows a toast error
UI Elements:
InputOTPcomponent with 8 slots- Back link to
/login - Wrapped in
Suspense(required foruseSearchParamsin Next.js)
Onboarding Page
Route: /onboard
File: app/onboard/page.tsx
Shown to first-time users who have authenticated but haven't completed their profile.
Form Fields:
- First name (required)
- Last name (required)
- School selection dropdown
- Fetches schools from
GET /api/schools - Includes a "Create School" option that opens a dialog
- Fetches schools from
- Create School dialog (if school doesn't exist):
- Name, code, school type (primary/secondary), parish dropdown (Grenada parishes), address, email, phone
Flow:
- User fills in name and selects/creates a school
- Calls
PATCH /api/auth/onboardwithfirstName,lastName,schoolId - On success → redirect to
/dashboard
Authentication State
Tokens are managed in lib/auth.ts:
| Storage | Key | Purpose |
|---|---|---|
| localStorage | gb_access_token | JWT for API requests |
| localStorage | gb_refresh_token | Token for refreshing expired JWTs |
| Cookie | gb_logged_in | Flag for route protection (30-day expiry) |
The setTokens() function sets all three. clearTokens() removes them on logout.