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.

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

Terminal window
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=/

Include the cookie on subsequent requests:

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

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

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

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

Three authorization policies control access:

PolicyRolesApplied To
ViewerOrAboveviewer, editor, adminRead endpoints (GET teams, principles, objectives, history, SSE, export)
EditorOrAboveeditor, adminEvent submission (POST events)
AdminOnlyadminUser management, global event log

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

  • update_team_color, restore_history, import_team
  • create_entity, delete_entity, update_name when targetType is "Team"

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

PropertyValue
Cookie nametechstrat_session
Lifetime7 days from creation
StoragePostgreSQL sessions table
CacheIn-memory, 5-minute TTL

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

To verify your authentication status and retrieve your user info:

Terminal window
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.

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)

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