Skip to content

API Authentication

This page covers the practical details of authenticating with the Tech Strategy Tool API, including login flow, session management, and CSRF requirements.

Overview

The API uses cookie-based session authentication. After logging in, a session cookie is set on the browser and automatically included in subsequent requests.

Login Flow

1. Authenticate

curl -X POST https://localhost:5001/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "editor", "password": "editor"}' \
  -c cookies.txt

On success, the server sets the techstrat_session cookie:

Set-Cookie: techstrat_session=<session-id>; HttpOnly; Secure; SameSite=Strict; Path=/

2. Make authenticated requests

Include the cookie on subsequent requests:

curl https://localhost:5001/api/teams \
  -b cookies.txt

3. Make mutating requests

All POST, PUT, PATCH, and DELETE requests require the CSRF header:

curl -X POST https://localhost:5001/api/events \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: 1" \
  -b cookies.txt \
  -d '{"eventType": "create_team", "data": {"id": "...", "name": "New Team", "color": "#3498db"}}'

4. Logout

curl -X POST https://localhost:5001/api/auth/logout \
  -H "X-CSRF-Token: 1" \
  -b cookies.txt

CSRF Protection

All mutating API requests must include the header:

X-CSRF-Token: 1

The value is always the string 1. This prevents cross-site request forgery by ensuring the request was made from JavaScript code (browsers cannot set custom headers on cross-origin form submissions without CORS preflight).

Exempt from CSRF: POST /api/auth/login (no session exists yet).

If the header is missing on a mutating request, the API returns:

HTTP/1.1 403 Forbidden

Roles and Permissions

Three authorization policies control access:

Policy Roles Applied To
ViewerOrAbove viewer, editor, admin Read endpoints (GET teams, principles, objectives, history, SSE, export)
EditorOrAbove editor, admin Event submission (POST events)
AdminOnly admin User management, global event log

Additionally, certain events submitted through POST /api/events require admin role even though the endpoint only requires EditorOrAbove:

  • create_team, update_team_name, update_team_color, delete_team
  • restore_history

Non-admin users attempting these events receive a 403 response.

Session Details

Property Value
Cookie name techstrat_session
Lifetime 7 days from creation
Storage PostgreSQL sessions table
Cache In-memory, 5-minute TTL

Sessions are cleaned up automatically by a background service that runs hourly.

Check Current Session

To verify your authentication status and retrieve your user info:

curl https://localhost:5001/api/auth/me \
  -b cookies.txt

Response (200):

{
  "success": true,
  "userId": "a1b2c3d4-...",
  "username": "editor",
  "role": "editor",
  "error": null
}

Response (401): Session is invalid or expired.

Rate Limiting

Login attempts are rate-limited per username:

  • Threshold: 5 failed attempts within 15 minutes
  • Lockout: Account is temporarily locked after threshold is reached
  • Reset: Successful login clears the failure counter
  • Scope: In-memory only (resets on application restart)

Blazor Client Integration

Both Blazor WASM applications handle authentication automatically:

  • The browser sends the techstrat_session cookie with every request (same-origin)
  • The API clients (StrategyApiClient and AdminApiClient) include X-CSRF-Token: 1 on all mutating requests
  • Session state is tracked in the application state services (StrategyState and AdminState)
  • Unauthenticated users are redirected to the login page