Skip to main content
Auth lives in src/lib/auth.js and is mounted at /api/auth/[...nextauth]. The edge proxy (src/proxy.js) enforces a session on /dashboard, /form, /view, /admin, and /api (except /api/public and NextAuth).

Roles and access

What each level can view and edit on a plan.

Role preview

Super Admin JWT impersonation of demo Principal and AP accounts.

Sign-in rules

A Google account can enter the app only when all of the following are true:
  1. Email ends with @schools.nyc.gov (Google hd is set to that domain; the callback still checks the suffix).
  2. A matching User document exists (email lowercase, unique).
  3. isActive is not false.
  4. NextAuth signIn callback returns true.
Otherwise the user is sent back to /login. Inactive accounts cannot sign in even if the Google mailbox is valid. Sign-in rejection Caption: Add screenshot showing the login error when the Google account is not pre-registered or is not a DOE email.
Provider checks: PKCE, state, and nonce. prompt is select_account. Cookies are Secure when NEXTAUTH_URL starts with https://.
Level is not self-service. Only Super Admin (5) can create level 4–5 users. Principals (4) may create levels 1–3 for their school. Demo d79.demo.* users cannot Google-sign-in.

Session

JWT callback copies from MongoDB onto the token. Session callback exposes:
API routes call getServerSession(authOptions) and then re-load User by session email for authorization. During role preview, that email is the demo user. Each token has a jti. On signOut, Redis stores sess:deny:{jti} until expiry so the cookie cannot be reused. Proxy rejects denied tokens with 401.

Client usage

Public pages (/, /about) still fetch /api/public/overview without a session. If status === 'authenticated', the portal CTA becomes Open dashboard.