Authentication
Overview
Section titled “Overview”PinTeach uses cookie-based session authentication with two auth flows:
- Teachers: Google OAuth
- Students: Magic Links (email-based, zero friction)
Session cookie: pinteach_session (30-day expiry)
Auth Routes
Section titled “Auth Routes”| Method | Path | Description |
|---|---|---|
| GET | /auth/google | Start Google OAuth → redirect to consent |
| GET | /auth/google/callback | OAuth callback → creates/finds teacher, sets cookie |
| GET | /auth/me | Current user (teacher or student) |
| POST | /auth/magic-link | Send magic link to student (5/hr rate limit) |
| POST | /auth/verify-magic-link | Verify token → set cookie |
| POST | /auth/stop-impersonation | Exit teacher impersonation |
| POST | /auth/logout | Destroy session, clear cookies |
| GET | /auth/dev-login/:teacherId | DEV ONLY: Direct login |
Teacher Auth (Google OAuth)
Section titled “Teacher Auth (Google OAuth)”1. Teacher clicks "Login with Google"2. Redirect to Google consent screen3. Google redirects back with auth code4. Backend exchanges code for tokens5. Creates/finds teacher record6. Creates session in auth_sessions table7. Sets pinteach_session cookie (30 days)Student Auth (Magic Links)
Section titled “Student Auth (Magic Links)”1. Student enters email on public page2. Backend sends email with magic link token3. Student clicks link in email4. Backend verifies token → creates session5. Sets pinteach_session cookie (30 days)POST /auth/magic-link
Section titled “POST /auth/magic-link”{ "teacherSlug": "maria-garcia"}Response: { "sent": true }
Rate limited to 5/hr per IP.
/auth/me Response
Section titled “/auth/me Response”Teacher
Section titled “Teacher”{ "role": "teacher", "teacher": { "id": "uuid", "name": "Maria Garcia", "slug": "maria-garcia", "avatarUrl": "...", "timezone": "Europe/Madrid", "onboardingCompleted": true }}Student
Section titled “Student”{ "role": "student", "student": { "id": "uuid", "name": "John Smith", "timezone": "America/New_York" }, "impersonating": false}Impersonation
Section titled “Impersonation”Teachers can impersonate students to view their portal:
POST /teacher/students/:id/impersonateA secondary cookie preserves the teacher session. Exit with POST /auth/stop-impersonation.
Auth Plugin
Section titled “Auth Plugin”The Fastify auth plugin (plugins/auth.ts) decorates the request:
request.teacherId— set for teacher routesrequest.studentId— set for student routes
Routes under /teacher/ require teacher auth. Routes under /student/ require student auth.
Dev Login
Section titled “Dev Login”For local development only:
GET /api/auth/dev-login/00000000-0000-4000-a000-000000000001Sets the session cookie without OAuth flow. Disabled in production.