Skip to main content

Authentication

Baby Basics uses session-based authentication with bearer tokens. All authenticated endpoints require an Authorization header with a valid session token.

Authentication Flow

  1. Register a new account or log in with existing credentials
  2. Receive a session token in the response
  3. Include the token in the Authorization header for all subsequent requests
  4. 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:

StatusCodeDescription
400VALIDATION_ERRORInvalid request body (password too short, invalid email, etc.)
409CONFLICTEmail already registered

Validation Rules:

  • name: Required, 1-100 characters, trimmed
  • email: Required, valid email format, converted to lowercase
  • password: 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_SECRET environment 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:

  1. ServerURLView: Validates server URL via GET /health before allowing auth
  2. OnboardingFlow: Manages the auth flow with three paths:
    • Create Account
    • I Have an Invite (register + accept invite)
    • Log In
  3. AuthManager: Handles token storage in Keychain with reinstall detection
  4. APIClient: Automatically includes token in Authorization header

See the iOS Onboarding spec for details.