Project 1 - Admin Panel
Admin Panel - Backend & Auth
The Admin Panel uses a custom Node.js backend with Next.js API routes, JWT in HTTP-only cookies, and server actions for auth and forms.
Stack
- PostgreSQL via
pg - JWT for sessions (HTTP-only cookies)
- bcrypt for PIN hashing
- Next.js API Routes for REST endpoints
- Server Actions for form submissions (login, register, etc.)
Auth API Routes
Under src/app/api/auth/:
| Method | Route | Purpose |
|---|---|---|
| POST | /api/auth/send-pin | Generate and send PIN (e.g. for signup); in dev often mock |
| POST | /api/auth/verify-signup | Verify PIN and create account |
| POST | /api/auth/signin | Sign in with phone + PIN |
| GET | /api/auth/me | Return current user profile (requires auth cookie) |
Server Actions
In src/lib/auth/actions.ts:
sendSignUpPIN()– Generate/send PIN for signupverifySignUpPIN()– Verify PIN and create accountsignInWithPhoneAndPin()– Sign insendForgotPinOTP()– Forgot PIN flowsignOut()– Sign out
Database Layer
src/lib/db/index.ts– DB connection poolsrc/lib/db/users.ts– User/profile queries
Authentication Flow
Sign up
- User enters phone number.
- App calls send-pin (or server action); system generates 4-digit PIN (in dev often
1234). - PIN is “sent” (in dev may only be logged).
- User enters PIN; app calls verify-signup (or server action).
- Account is created with hashed PIN; JWT is set in HTTP-only cookie.
Sign in
- User enters phone + PIN.
- Server verifies PIN against stored hash, issues JWT, sets cookie.
Protected routes
- Middleware or server checks JWT from cookie.
- Role-based access (admin, instructor, user) is enforced in routes and server actions.
Env vars (auth/backend)
DATABASE_URL=postgresql://...
JWT_SECRET=your-strong-secret
JWT_EXPIRES_IN=7d
NEXT_PUBLIC_API_URL=http://localhost:3000
Production notes
- Use a strong
JWT_SECRET(e.g.openssl rand -base64 32). - Use HTTPS and secure cookies in production.
- Integrate a real SMS provider (e.g. Twilio) for PIN delivery.
- Store temporary PINs in Redis or DB with expiry; add rate limiting on send-pin/verify.
- Keep error messages user-friendly and avoid leaking internal details.
Testing auth endpoints
# Send PIN (signup)
curl -X POST http://localhost:3000/api/auth/send-pin \
-H "Content-Type: application/json" \
-d '{"phone":"1234567890"}'
# Verify signup
curl -X POST http://localhost:3000/api/auth/verify-signup \
-H "Content-Type: application/json" \
-d '{"phone":"1234567890","pin":"1234","fullName":"Test User"}'
# Sign in
curl -X POST http://localhost:3000/api/auth/signin \
-H "Content-Type: application/json" \
-d '{"phone":"1234567890","pin":"1234"}'
# Current user (use cookie from signin response)
curl -X GET http://localhost:3000/api/auth/me \
-H "Cookie: auth_token=YOUR_JWT"
See Login & Credentials for how to log in in the UI and use mock PIN in development.