Skip to main content

Authentication

Most endpoints require an authenticated session. The pwa-admin-core backend uses a JWT delivered in an HttpOnly cookie, combined with XSRF double-submit protection. There is also a server-to-server (S2S) path based on API keys.

:::info What the OpenAPI spec declares The generated spec formally declares a single security scheme — an API-key cookie named Sec-AT (the access token). The XSRF and S2S details below are part of the backend's security model but are not expressed in the OpenAPI document, which is exactly why this page exists. :::

1. Session auth (browser / dashboard)

On successful login the backend sets an HttpOnly, Secure cookie carrying a JWT (declared in the spec as Sec-AT). Because the cookie is HttpOnly:

  • JavaScript cannot read it (this is deliberate — it mitigates token theft via XSS).
  • The browser attaches it automatically to same-site requests, so you normally don't set any Authorization header yourself.

XSRF (double-submit) protection

Cookie-based auth is vulnerable to cross-site request forgery, so state-changing requests (POST, PUT, PATCH, DELETE) additionally require an XSRF token using the double-submit pattern:

  1. The backend issues an XSRF cookie (Sec-XSRF) — this one is not HttpOnly, so the frontend can read it.
  2. On each mutating request, the client copies that value into the X-XSRF-TOKEN request header.
  3. The backend accepts the request only when the cookie value and the header value match.

Safe, read-only requests (GET, HEAD) do not require the XSRF header.

Typical login flow

# 1. Log in — the server sets the access + XSRF cookies into cookies.txt
curl -i -c cookies.txt \
-X POST http://localhost:8080/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"••••••"}'

# 2. Read the XSRF cookie value that the server just set
XSRF=$(grep -i 'Sec-XSRF' cookies.txt | awk '{print $NF}')

# 3. Call a mutating endpoint: send cookies back + the XSRF header
curl -i -b cookies.txt \
-X POST http://localhost:8080/pwa \
-H 'Content-Type: application/json' \
-H "X-XSRF-TOKEN: ${XSRF}" \
-d '{"name":"My PWA"}'

# 4. A read-only call only needs the cookies
curl -s -b cookies.txt http://localhost:8080/pwa

2. Server-to-server (S2S)

For machine-to-machine integrations the backend accepts API keys sent as request headers instead of the session cookie:

  • X-API-Key — the integration/application key.
  • X-User-Api-Key — the key identifying the acting user, where required.
curl -s http://localhost:8080/s2s/event \
-H 'X-API-Key: <application-key>' \
-H 'X-User-Api-Key: <user-key>' \
-H 'Content-Type: application/json' \
-d '{ ... }'

S2S requests are not subject to the XSRF check (there is no browser cookie to forge).

Public IDs

Every public identifier returned or accepted by the API is an opaque, prefixed string — never a raw database number:

pwa_a1b2c3d4 user_x9y8z7w6 team_k3m5n7p9

Treat them as opaque tokens: store and echo them verbatim, never parse or increment them. In the spec they are typed as string.

Trying requests

The interactive "Try it" button is disabled in this documentation on purpose:

  • The access token lives in an HttpOnly cookie that in-browser JavaScript cannot set or read.
  • The docs site and the API are on different origins, so CORS and cookie SameSite rules block the request the widget would make.

Rather than presenting a control that always fails, we provide curl examples you can copy and run from a terminal (see above). To explore interactively against a running backend, use the backend's own Swagger UI at http://localhost:8080/swagger-ui.html, which shares the API's origin.