Files
login-example-app/docs/superpowers/specs/2026-05-21-login-auth-design.md
2026-05-21 18:44:41 +02:00

6.0 KiB
Raw Blame History

Login Authentication Design (Next.js, PostgreSQL, Brevo SMTP)

1. Overview & Tech Stack

Component Technology Reason
Frontend / SSR Next.js 13 (App Router) Filebased routing, SSR/SSG, builtin API routes
Database PostgreSQL (selfhosted, EU datacenter) ACID, atrest encryption, works with Prisma
ORM Prisma 2 Typesafe queries, easy migrations
Password hashing bcrypt (cost=12) Industrystandard, slow enough to deter bruteforce
Tokens JWT (HS256) Access token ~15min, Refresh token ~7days
Session cookies HttpOnly + Secure + SameSite=Lax (chosen by user) XSS/CSRF protection
Email service Brevo SMTP GDPRcompatible, simple configuration
Deployment Vercel (serverless API routes) Automatic builds, EU region, zeroconfig
Testing Jest + React Testing Library, Supertest for API Unit & integration coverage

2. Database Schema (Prisma)

model User {
  id            String   @id @default(cuid())
  email         String   @unique
  passwordHash  String
  role          Role     @default(USER)
  emailVerified Boolean  @default(false)
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  verificationTokens VerificationToken[]
  passwordResetTokens PasswordResetToken[]
}

model VerificationToken {
  id        String   @id @default(cuid())
  token     String   @unique
  expiresAt DateTime
  userId    String
  user      User     @relation(fields: [userId], references: [id])
  createdAt DateTime @default(now())
}

model PasswordResetToken {
  id        String   @id @default(cuid())
  token     String   @unique
  expiresAt DateTime
  used      Boolean  @default(false)
  userId    String
  user      User     @relation(fields: [userId], references: [id])
  createdAt DateTime @default(now())
}

enum Role {
  ADMIN
  USER
}

3. API Routes (Next.js /pages/api/...)

Route Method Purpose Input Output
/api/auth/register POST Create user, hash password, send verification mail { email, password } 201 Created, message "Verification mail sent"
/api/auth/verify-email GET Validate verification token, set emailVerified ?token= 200 OK, "Email verified"
/api/auth/login POST Check credentials, issue access & refresh JWT, set cookies { email, password, rememberMe? } 200 OK, cookies set
/api/auth/logout POST Clear cookies, optionally blacklist refresh token 200 OK
/api/auth/refresh-token POST Verify refresh JWT, issue new access JWT (rotate refresh if >2days) (refresh cookie) 200 OK, new cookies
/api/auth/request-password-reset POST Create reset token, send mail { email } 200 OK, message "Mail sent"
/api/auth/reset-password POST Validate reset token, store new bcrypt hash, invalidate token { token, newPassword } 200 OK
/api/auth/me GET Return current user data (no password) 200 OK, { email, role, emailVerified }

All endpoints enforce Content-Type: application/json and Cache-Control: no-store.

4. Email Workflow (Brevo SMTP)

  1. Registration creates a VerificationToken (UUID + HMAC) stored with an expiry (24h).
  2. Email template (HTML + text) contains a link: https://<yourapp>.vercel.app/api/auth/verify-email?token=<<token>>
  3. The verification endpoint validates the token, marks the user as verified and deletes the token.
  4. Passwordreset works analogously with a onehour token and a used flag.

SMTP credentials (BREVO_SMTP_HOST, BREVO_SMTP_USER, BREVO_SMTP_PASS) are stored as Vercel environment variables.

Cookie Content Max Age SameSite Secure HttpOnly
accessToken JWT (sub, role, exp) 15min Lax (as requested) true true
refreshToken JWT (sub, exp) 7days (user chose "remember me") Lax true true

Refresh token is only set when the frontend sends rememberMe: true.

6. Role & Permission System

  • requireAuth middleware validates the access token and attaches req.user.
  • requireRole('ADMIN') middleware checks req.user.role.
  • Roles are stored in the role column of User and encoded into the JWT payload.

7. GDPR & DataMinimisation

Measure Implementation
Minimal data Store only email, hashed password, role, verification flag.
Consent Registration form includes a mandatory "I accept the privacy policy" checkbox.
Right to be forgotten DELETE /api/users/me removes the user row and all related tokens.
Data retention Verification and reset tokens have explicit expiresAt; nightly Prisma job deletes expired rows.
Transport security All traffic forced via HTTPS (Vercel provides TLS).
Atrest encryption PostgreSQL instance encrypted by the managed provider (EU region).
Audit log Optional AuditLog table with pseudonymised entries, retained 30days.

8. Deployment Pipeline (Vercel)

  1. Connect the GitHub repo to Vercel.
  2. Vercel runs npm install && npm run build && npm test on each push.
  3. Preview deployments for PRs (pr<num>--<repo>.vercel.app).
  4. Production deploy on merge to main (https://<app>.vercel.app).
  5. Environment variables (DATABASE_URL, NEXTAUTH_SECRET, Brevo SMTP creds) are configured in Vercel > Settings > Environment Variables same values for Preview and Production.

9. Security Checklist

  • bcrypt cost=12
  • HttpOnly+Secure+SameSiteLax cookies
  • Refreshtoken rotation on each refresh
  • Rate limiting on /login and /request-password-reset
  • CSP, XContentTypeOptions, ReferrerPolicy headers via next.config.js
  • Helmetlike security headers
  • Regular dependency audit (npm audit) and CI fail on high severity issues

This spec is ready for review. Once approved, the next step will be to create a detailed implementation plan.