Authentication

May 2, 2026 · View on GitHub

The API uses JWT (JSON Web Tokens) with refresh token support.

Login

POST /auth
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "user_password"
}

Response:

{
  "access_token": "eyJ...",
  "refresh_token": "dGhp...",
  "user_id": "user-uuid",
  "expires_in": 3600
}

Refresh Access Token

POST /auth/refresh
Content-Type: application/json

{
  "refresh_token": "dGhp..."
}

Response (same shape as login):

{
  "access_token": "eyJ...",
  "refresh_token": "dGhp...",
  "user_id": "user-uuid",
  "expires_in": 3600
}

By default the same refresh token is returned. Pass ?rotate=true to issue a fresh refresh token (rotating invalidates the old one).

Logout

POST /auth/logout
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "refresh_token": "dGhp..."
}

Logout from all devices:

POST /auth/logout-all
Authorization: Bearer <access_token>

Token Details

  • Access token: Short-lived (1 hour). Include in Authorization: Bearer <token> header.
  • Refresh token: Long-lived (30 days). Used to obtain new access tokens without re-login. Stored in the refresh_tokens database table; can be revoked via /auth/logout (single token) or /auth/logout-all (all tokens for the user).

OAuth2 Client Credentials

For service-to-service authentication (e.g., admin tooling):

POST /api/v1/oauth/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "<CLIENT_ID>",
  "client_secret": "<CLIENT_SECRET>"
}

Tokens are valid for 30 minutes.

Common Authentication Errors

StatusMeaning
401 UnauthorizedAccess token expired — use refresh token to get a new one
401 UnauthorizedRefresh token invalid or expired — user must log in again
403 ForbiddenValid token but insufficient permissions for the requested operation

Troubleshooting

# Check if refresh tokens are being created
docker compose logs <service_name> | grep -i "refresh"

# Verify refresh token table exists
docker compose exec database psql -U root -d gefdb -c "\d refresh_tokens"

# Clean up expired tokens
docker compose run --rm api python -c "
from gefapi.services.refresh_token_service import RefreshTokenService
print(f'Cleaned up {RefreshTokenService.cleanup_expired_tokens()} expired tokens')
"