Skip to content

Admin Console — Sessions & CSRF

The admin console at https://admin.proxy.worv.ai uses Flask cookie sessions, not API keys.

POST /api/login

Authenticate with username/password. Issues a session cookie + CSRF token.

Auth None
Rate limit 10 / minute / IP
CSRF Not required

Request

POST /api/login HTTP/1.1
Host: admin.proxy.worv.ai
Content-Type: application/json

{
  "username": "admin",
  "password": "..."
}

Responses

Status Body
200 {"ok": true, "username": "<u>", "csrf_token": "<hex>"} plus Set-Cookie: session=...
401 {"error": "Invalid credentials"}
429 rate-limit exhausted

The admin password is auto-generated on first boot and printed to the proxy's stdout / journal. Override with the ADMIN_PASSWORD env var when starting glm-proxy.service.

POST /api/logout

Tear down the session.

Auth Session
CSRF Required (X-CSRF-Token header or _csrf JSON field)

Response

200 {"ok": true} and Set-Cookie: session= (cleared).

GET /api/me

Probe whether the caller has a live session.

Responses

Condition Status Body
Authenticated 200 {"authenticated": true, "username": "<u>", "csrf_token": "<hex>"}
Anonymous 401 {"authenticated": false}

The csrf_token here is the same one issued at login — safe to re-fetch when reloading a page; it does not rotate on read.

CSRF mechanics

State-changing methods (POST, PATCH, DELETE) on /api/* authenticated endpoints require a CSRF token via either:

  • X-CSRF-Token: <hex> header, or
  • "_csrf": "<hex>" field in the JSON body.

Both must equal the csrf_token stored in the session. secrets.compare_digest is used so timing-attack resistance is built in.

Method Authenticated CSRF check
GET / HEAD / OPTIONS yes exempt
POST / PATCH / DELETE yes required
any no exempt (only login itself)

A missing or mismatched token returns 403 {"error":"CSRF token missing or invalid"}.

Attribute Value
HttpOnly yes
Secure yes
SameSite Lax
Lifetime 365 days (sliding; refreshed on each request)
Signature key SECRET_KEY env var (rotated by operator)
Cookie name session (Flask default)

Front-end code (web/) calls GET /api/me on load to bootstrap state; 401 should redirect to the login page.