Authentication
Baby Basics uses session-based authentication with bearer tokens. All authenticated endpoints require an Authorization header with a valid session token.
Authentication Flow
- Register a new account or log in with existing credentials
- Receive a session token in the response
- Include the token in the
Authorizationheader for all subsequent requests - Session tokens expire after 30 days of inactivity (rolling window)
Session Management
- Token Type: Random 64-character hex string (
crypto.randomBytes(32).toString('hex')) - Storage: Store securely in iOS Keychain (never UserDefaults)
- Expiry: 30-day sliding window - extends automatically on each authenticated request
- Refresh: No refresh tokens - the session token itself has a rolling expiry
- Multiple Sessions: Each login creates a new session (multi-device is supported)
Endpoints
Register
Create a new user account and receive a session token.
POST /api/v1/auth/register
Content-Type: application/json
{
"name": "Johnny",
"email": "parent@example.com",
"password": "securepassword123"
}
Success Response (201):
{
"session": {
"token": "abc123def456...",
"expires_at": "2026-03-16T12:00:00.000Z"
},
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "parent@example.com",
"name": "Johnny",
"timezone": "America/New_York",
"day_start_time": "07:00"
}
}
Error Responses:
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid request body (password too short, invalid email, etc.) |
| 409 | CONFLICT | Email already registered |
Validation Rules:
name: Required, 1-100 characters, trimmedemail: Required, valid email format, converted to lowercasepassword: Minimum 8 characters (no maximum, no complexity requirements)
Login
Authenticate with existing credentials and receive a session token.
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "parent@example.com",
"password": "securepassword123"
}
Success Response (200):
{
"session": {
"token": "abc123def456...",
"expires_at": "2026-03-16T12:00:00.000Z"
},
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "parent@example.com",
"name": "Johnny",
"timezone": "America/New_York",
"day_start_time": "07:00"
}
}
Error Response (401):
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid email or password",
"details": []
}
}
Security Notes:
- Error message is intentionally generic - doesn't reveal whether email exists
- Uses bcrypt constant-time comparison to prevent timing attacks
- Login failures are NOT logged to prevent audit log flooding
Logout
Invalidate the current session token.
POST /api/v1/auth/logout
Authorization: Bearer <your-session-token>
Success Response (204):
No Content
The session token is immediately invalidated and cannot be used again.
Admin Password Reset
Emergency password reset endpoint for MVP. Protected by server-side admin token (not for client use).
POST /api/v1/auth/reset-password
X-Admin-Token: <JWT_SECRET from .env>
Content-Type: application/json
{
"email": "parent@example.com",
"new_password": "newsecurepassword123"
}
Success Response (200):
{
"success": true
}
Notes:
- This is an escape hatch for MVP - proper password reset with email is post-MVP
- Requires the
JWT_SECRETenvironment variable value - All existing sessions for the user remain valid (force logout separately if needed)
- Password change is logged to AuditLog
Using Tokens
Include your session token in the Authorization header for all authenticated endpoints:
GET /api/v1/children
Authorization: Bearer abc123def456...
Token Expiry Response (401):
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired token",
"details": []
}
}
When you receive a 401 error, the user must log in again to obtain a new session token.
Security Best Practices
Password Storage
- Passwords are hashed with bcrypt (cost factor 12)
- Original passwords are never stored or logged
- Password changes are logged to AuditLog but only as
{password_changed: true}, never the actual password
Token Storage
- iOS: Store tokens in Keychain (NOT UserDefaults)
- Never include tokens in logs, analytics, or error reports
- Tokens are treated as sensitive credentials
Rate Limiting
- Auth endpoints are rate-limited by IP address: 5 requests per minute
- Prevents brute force attacks
- Other endpoints are rate-limited per authenticated user: 100 requests per minute
Audit Logging
All authentication events are logged to the AuditLog table:
- ✅ Register success
- ✅ Login success
- ✅ Logout
- ✅ Password reset
- ❌ Login failures (NOT logged to prevent flooding)
iOS Implementation
The iOS app handles authentication through:
- ServerURLView: Validates server URL via
GET /healthbefore allowing auth - OnboardingFlow: Manages the auth flow with three paths:
- Create Account
- I Have an Invite (register + accept invite)
- Log In
- AuthManager: Handles token storage in Keychain with reinstall detection
- APIClient: Automatically includes token in
Authorizationheader
See the iOS Onboarding spec for details.