Overview
JWT-based authentication with NextAuth.js and Django backend.
HyperSaaS uses NextAuth.js v5 (Auth.js) with a credentials provider that authenticates against the Django backend's Djoser JWT endpoints.
Architecture
Browser Next.js Django
│ │ │
│ email + password │ │
│─────────────────────────►│ POST /auth/jwt/create/ │
│ │──────────────────────────►│
│ │ ◄── {access, refresh} ───│
│ │ │
│ │ GET /auth/users/me/ │
│ │──────────────────────────►│
│ │ ◄── user details ────────│
│ │ │
│ ◄── session cookie ─────│ Store tokens in JWT │
│ │ │
│ API request │ │
│─────────────────────────►│ Authorization: JWT {token}│
│ │──────────────────────────►│Key Components
| Component | Location | Purpose |
|---|---|---|
| NextAuth Config | lib/auth/providers.ts | Credentials provider, JWT callbacks |
| Token Utilities | lib/auth/utils.ts | Validate, refresh, extract tokens |
| Server Session | lib/auth/session.ts | Get current user on server |
| Auth Actions | lib/auth/actions.ts | Login/logout server actions |
| Middleware | middleware.ts | Protect routes |
Auth Pages
| Page | Route | Description |
|---|---|---|
| Login | /login | Email + password form |
| Register | /register | Account creation → email verification |
| Activate | /user-activation/[uid]/[token] | Email verification link |
| Reset Password | /reset-password | Request password reset email |
| Confirm Reset | /confirm-password-reset/[uid]/[token] | Set new password |
| Resend Activation | /resend-activation | Request new activation email |
| Change Email | /reset-username | Emails a link to the current address |
| Choose New Email | /confirm-username-reset/[uid]/[token] | Sends a confirmation link to the new address |
| Confirm Email Change | /confirm-email-change/[token] | Makes the change; the old address is told |
The backend answers a wrong password and an account not yet activated the same way, so a failed sign-in says it could be either.
Session Shape
The NextAuth session holds who you are and the backend's access token; the refresh token stays in the encrypted session cookie:
interface Session {
user: {
id: string;
name?: string | null;
email?: string | null;
};
accessToken?: string;
error?: "RefreshAccessTokenError";
}Plans belong to workspaces, so the session carries no subscription details; the workspace layout reads them from /api/workspaces/{id}/plan/. After the account settings change your name or email, the page calls useSession().update(), and the session reads them again from /auth/users/me/.
Token Refresh
Tokens are automatically refreshed 60 seconds before expiry in the NextAuth JWT callback. If refresh fails, the session is invalidated and the user is redirected to login.