Authentication API
Identity and Session Management
Register users, issue sessions, complete onboarding, and manage API keys
This page documents the non-admin authentication surface from the backend code. It covers the
real /api/auth routes plus user-owned /api/api-keys management.
JWT bearerRefresh cookiesCSRF for browser mutationsMFA and OAuth
Source
- Controller:
backend-nestjs/src/auth/auth.controller.ts - DTOs:
backend-nestjs/src/dto/auth.dto.ts,backend-nestjs/src/dto/onboarding.dto.ts - User API keys controller:
backend-nestjs/src/api-security/controllers/api-key.controller.ts - User API key DTOs:
backend-nestjs/src/api-security/dto/api-key.dto.ts - JWT guard:
backend-nestjs/src/auth/guards/jwt-auth.guard.ts - CSRF middleware:
backend-nestjs/src/common/middleware/csrf-protection.middleware.ts
Authentication Model
| Mode | Where it applies | Notes |
|---|---|---|
| Public | registration, login, availability checks, refresh, OAuth callbacks | No bearer token required |
| JWT bearer | most signed-in routes | Authorization: Bearer <token> |
| Refresh cookie | browser refresh/logout flow | POST requests still need CSRF when cookie-authenticated |
| User API key | selected routes protected by JwtAuthGuard | Send x-api-key or Authorization: ApiKey <token> |
| JWT only | /api/api-keys management endpoints | These use AuthGuard('jwt'), not the broader JwtAuthGuard |
Important implementation notes:
JwtAuthGuardalso supports user API keys whenApiKeyServiceis wired in.- Incomplete-onboarding users are blocked from most non-
/authroutes until onboarding is finished. - Browser-based mutating requests use CSRF protection and must include
x-csrf-token.
Endpoint Reference
Auth Controller
| Method | Path | Purpose | Request or query | Auth | Source |
|---|---|---|---|---|---|
GET | /api/auth/csrf | Issue or return the active CSRF token. | None | Public | auth/auth.controller.ts |
POST | /api/auth/register | Create a new user and issue session tokens. | Body: username,email,password,firstName,lastName,role | Public | auth/auth.controller.ts |
POST | /api/auth/login | Create a session for an existing user. | Body: username,password,captchaToken,honeypot,mfaCode,mfaRecoveryCode | Public | auth/auth.controller.ts |
GET | /api/auth/username-availability | Check whether a username is free. | Query: username | Public | auth/auth.controller.ts |
GET | /api/auth/email-availability | Check whether an email is free. | Query: email | Public | auth/auth.controller.ts |
GET | /api/auth/profile | Read the authenticated user profile snapshot. | None | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/complete-onboarding | Finish the onboarding wizard for the current user. | Body: onboarding fields | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/refresh | Rotate the refresh token and issue a new access token. | Body: refreshToken or refresh cookie | Public session flow | auth/auth.controller.ts |
POST | /api/auth/logout | Revoke the current refresh token family and clear browser cookies. | Body: optional refreshToken | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/widget-token | Issue the Android widget token. | None | JWT or user API key | auth/auth.controller.ts |
GET | /api/auth/mfa/status | Read MFA setup or enabled status. | None | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/mfa/setup | Start TOTP setup and return provisioning material. | None | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/mfa/enable | Verify a TOTP code and enable MFA. | Body: code | JWT or user API key | auth/auth.controller.ts |
POST | /api/auth/mfa/disable | Disable MFA with a current code or recovery code. | Body: code,recoveryCode | JWT or user API key | auth/auth.controller.ts |
GET | /api/auth/google | Start Google OAuth. | None | Public redirect | auth/auth.controller.ts |
GET | /api/auth/google/callback | Google OAuth callback. | Provider query params | Public callback | auth/auth.controller.ts |
GET | /api/auth/microsoft | Start Microsoft OAuth. | None | Public redirect | auth/auth.controller.ts |
GET | /api/auth/microsoft/callback | Microsoft OAuth callback. | Provider query params | Public callback | auth/auth.controller.ts |
User API Keys
| Method | Path | Purpose | Request or query | Auth | Source |
|---|---|---|---|---|---|
GET | /api/api-keys | List the current user's API keys. | None | JWT bearer only | api-security/controllers/api-key.controller.ts |
POST | /api/api-keys | Create a new API key. | Body: name,scopes,tier,expiresInDays,rotateInDays | JWT bearer only | api-security/controllers/api-key.controller.ts |
POST | /api/api-keys/:id/rotate | Rotate an API key and return the new plaintext secret once. | Path: id | JWT bearer only | api-security/controllers/api-key.controller.ts |
DELETE | /api/api-keys/:id | Revoke an API key. | Path: id | JWT bearer only | api-security/controllers/api-key.controller.ts |
Request Shapes
Register
RegisterDto in backend-nestjs/src/dto/auth.dto.ts
username: required, sanitized, safe text, 3 to 64 charsemail: required, lowercased, valid email, max 254 charspassword: required, 6 to 128 chars, strong-password validatorfirstName: optional, safe text, max 80 charslastName: optional, safe text, max 80 charsrole: optional enumUserRole
Login
LoginDto in backend-nestjs/src/dto/auth.dto.ts
username: required, 1 to 254 chars, username or emailpassword: required, 1 to 128 charscaptchaToken: optional, max 2048 charshoneypot: optional, max 120 chars, should stay emptymfaCode: optional, must match^\d{6}$mfaRecoveryCode: optional, max 32 chars
Complete onboarding
CompleteOnboardingDto in backend-nestjs/src/dto/onboarding.dto.ts
username: optional, 3 to 64 chars,[a-zA-Z0-9_.]+firstName: optional, max 80 charslastName: optional, max 80 charsprofilePictureUrl: optional URL, max 2048 charslanguage: required enumen|de|fr|hutimezone: required IANA timezone, max 100 charstimeFormat: required12h|24hweekStartDay: required integer0..6defaultCalendarView: requiredmonth|weekthemeColor: required, one of the allowed onboarding palette colorsprivacyPolicyAccepted: required, must betruetermsOfServiceAccepted: required, must betrueproductUpdatesEmailConsent: optional booleanprivacyPolicyVersion: optional, max 64 charstermsOfServiceVersion: optional, max 64 charscalendarUseCase: optional enumpersonal|business|team|othersetupGoogleCalendarSync: optional booleansetupMicrosoftCalendarSync: optional boolean
MFA
EnableMfaDto.code: required 6-digit stringDisableMfaDto.code: optional 6-digit stringDisableMfaDto.recoveryCode: optional, max 32 chars
User API keys
CreateApiKeyDto in backend-nestjs/src/api-security/dto/api-key.dto.ts
name: required, safe text, max 120 charsscopes: optional enum arrayread|write|admintier: optional enumguest|user|premiumexpiresInDays: optional integer, minimum1rotateInDays: optional integer, minimum1
Example Calls
Bootstrap a browser session
curl "$PRIMECAL_API/api/auth/csrf" -c cookies.txt
curl -X POST "$PRIMECAL_API/api/auth/login" \
-b cookies.txt \
-c cookies.txt \
-H "Content-Type: application/json" \
-H "x-csrf-token: $CSRF_TOKEN" \
-d '{
"username": "mayblate",
"password": "StrongPassword123!"
}'
Complete onboarding
curl -X POST "$PRIMECAL_API/api/auth/complete-onboarding" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"timezone": "Europe/Budapest",
"timeFormat": "24h",
"weekStartDay": 1,
"defaultCalendarView": "week",
"themeColor": "#3b82f6",
"privacyPolicyAccepted": true,
"termsOfServiceAccepted": true,
"calendarUseCase": "personal"
}'
Create a user API key
curl -X POST "$PRIMECAL_API/api/api-keys" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "calendar-sync-job",
"scopes": ["read", "write"],
"tier": "user",
"expiresInDays": 90,
"rotateInDays": 30
}'
Response Notes
AuthResponseDtoreturnsaccess_token,token_type,expires_in,refresh_expires_at,issued_at, optionalrefresh_token, and auserblock.- Native clients can receive a plaintext
refresh_token; browser flows rely on the refresh cookie. - API key creation and rotation return the plaintext API key only once.
Best Practices
- Use
GET /api/auth/csrfbefore any cookie-backedPOST,PATCH,PUT, orDELETEcall from a browser client. - Treat
/api/auth/refreshas a session-maintenance endpoint, not a primary login path. - Keep MFA prompts conditional. Only send
mfaCodeormfaRecoveryCodewhen the login flow requires it. - Use user API keys for server-to-server user automation, but use JWT bearer auth for
/api/api-keysmanagement itself. - Prefer provider redirects from
/api/auth/googleand/api/auth/microsoftinstead of building your own OAuth URLs.