# Authentication Endpoints Complete reference for authentication API endpoints powered by BetterAuth. ## Base URL ``` http://localhost:3001/auth ``` All authentication endpoints are prefixed with `/auth`. ## Endpoints ### Sign Up Create a new user account with email and password. ```http POST /auth/sign-up ``` **Request Body:** ```json { "email": "user@example.com", "password": "SecurePass123!", "name": "John Doe" } ``` **Response (201):** ```json { "user": { "id": "user-uuid", "email": "user@example.com", "name": "John Doe", "emailVerified": false }, "session": { "id": "session-uuid", "token": "eyJhbGciOiJIUzI1NiIs...", "expiresAt": "2026-01-29T12:00:00.000Z" } } ``` **Errors:** - `409 Conflict` — Email already exists - `422 Validation Error` — Invalid input --- ### Sign In Authenticate with email and password. ```http POST /auth/sign-in ``` **Request Body:** ```json { "email": "user@example.com", "password": "SecurePass123!" } ``` **Response (200):** ```json { "user": { "id": "user-uuid", "email": "user@example.com", "name": "John Doe" }, "session": { "id": "session-uuid", "token": "eyJhbGciOiJIUzI1NiIs...", "expiresAt": "2026-01-29T12:00:00.000Z" } } ``` **Errors:** - `401 Unauthorized` — Invalid credentials --- ### Sign Out Invalidate current session. ```http POST /auth/sign-out ``` **Headers:** ```http Authorization: Bearer {session_token} ``` **Response (200):** ```json { "success": true } ``` --- ### Get Session Retrieve current session information. ```http GET /auth/session ``` **Headers:** ```http Authorization: Bearer {session_token} ``` **Response (200):** ```json { "user": { "id": "user-uuid", "email": "user@example.com", "name": "John Doe" }, "session": { "id": "session-uuid", "expiresAt": "2026-01-29T12:00:00.000Z" } } ``` **Errors:** - `401 Unauthorized` — Invalid or expired session --- ### Get Profile Get authenticated user's profile (custom endpoint). ```http GET /auth/profile ``` **Headers:** ```http Authorization: Bearer {session_token} ``` **Response (200):** ```json { "id": "user-uuid", "email": "user@example.com", "name": "John Doe", "emailVerified": false } ``` **Errors:** - `401 Unauthorized` — Not authenticated --- ### OIDC Callback OAuth callback handler for Authentik (and other OIDC providers). ```http GET /auth/callback/authentik ``` **Query Parameters:** - `code` — Authorization code from provider - `state` — CSRF protection token This endpoint is called by the OIDC provider after successful authentication. **Response:** - Redirects to frontend with session token --- ## Authentication Flow ### Email/Password Flow ``` 1. User submits credentials → POST /auth/sign-in 2. Server validates credentials 3. Server creates session 4. Server returns session token 5. Client stores token 6. Client includes token in subsequent requests ``` ### OIDC Flow ``` 1. User clicks "Sign in with Authentik" 2. Frontend redirects to Authentik 3. User authenticates with Authentik 4. Authentik redirects to /auth/callback/authentik 5. Server exchanges code for tokens 6. Server creates/updates user 7. Server creates session 8. Server redirects to frontend with session token ``` ## Using Session Tokens Include the session token in the `Authorization` header for all authenticated requests: ```http GET /api/tasks Authorization: Bearer eyJhbGciOiJIUzI1NiIs... ``` ### Token Storage **Frontend (Browser):** - Store in `httpOnly` cookie (most secure) - Or `localStorage` (less secure, XSS vulnerable) **Mobile/Desktop:** - Secure storage (Keychain on iOS, KeyStore on Android) ### Token Expiration Tokens expire after 24 hours (configurable via `JWT_EXPIRATION`). **Check expiration:** ```typescript import { AuthSession } from '@mosaic/shared'; const isExpired = (session: AuthSession) => { return new Date(session.session.expiresAt) < new Date(); }; ``` **Refresh flow** (future implementation): ```http POST /auth/refresh ``` ## Error Responses ### 401 Unauthorized ```json { "error": { "code": "UNAUTHORIZED", "message": "Invalid or expired session token" } } ``` ### 422 Validation Error ```json { "error": { "code": "VALIDATION_ERROR", "message": "Input validation failed", "details": { "email": "Invalid email format", "password": "Must be at least 8 characters" } } } ``` ## Examples ### Sign Up ```bash curl -X POST http://localhost:3001/auth/sign-up \ -H "Content-Type: application/json" \ -d '{ "email": "jane@example.com", "password": "SecurePass123!", "name": "Jane Doe" }' ``` ### Sign In ```bash curl -X POST http://localhost:3001/auth/sign-in \ -H "Content-Type: application/json" \ -d '{ "email": "jane@example.com", "password": "SecurePass123!" }' ``` **Save the token from response:** ```bash TOKEN=$(curl -X POST http://localhost:3001/auth/sign-in \ -H "Content-Type: application/json" \ -d '{"email":"jane@example.com","password":"SecurePass123!"}' \ | jq -r '.session.token') ``` ### Get Profile ```bash curl http://localhost:3001/auth/profile \ -H "Authorization: Bearer $TOKEN" ``` ### Sign Out ```bash curl -X POST http://localhost:3001/auth/sign-out \ -H "Authorization: Bearer $TOKEN" ``` ## Security Considerations ### Password Requirements - Minimum 8 characters - At least one uppercase letter - At least one lowercase letter - At least one number Configure in `apps/api/src/auth/auth.config.ts`. ### Rate Limiting - Sign-up: 5 requests per hour per IP - Sign-in: 10 requests per hour per IP (prevents brute force) ### CSRF Protection OIDC flow includes `state` parameter for CSRF protection. ### Token Security - Tokens are signed with `JWT_SECRET` - Use strong secret (min 32 characters) - Rotate secret regularly in production - Never expose tokens in logs ## TypeScript Types All authentication types are available from `@mosaic/shared`: ```typescript import type { AuthUser, AuthSession, LoginRequest, LoginResponse, } from '@mosaic/shared'; // Use in frontend const login = async (req: LoginRequest): Promise => { const res = await fetch('/auth/sign-in', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(req), }); return res.json(); }; // Use in backend @Post('sign-in') async signIn(@Body() request: LoginRequest): Promise { // ... } ``` See [API Types](2-types.md) for complete type definitions. ## Next Steps - **Configure OIDC** — [Configuration → Authentik](../../1-getting-started/3-configuration/2-authentik.md) - **Review Types** — [Authentication Types](2-types.md) - **Understand Architecture** — [Architecture → Authentication](../../3-architecture/2-authentication/1-betterauth.md)