Authentication
JWT Bearer access tokens and HttpOnly refresh cookies.
Login & register
POST /auth/register and POST /auth/login return an access token in the JSON body and set a refresh_token cookie. Always call the API with credentials: 'include' so cookies travel with requests.
fetch("$API/auth/login", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});API keys
JWT-only dashboard management creates pk_live_<32 hex lookup> and sk_live_<same lookup>_<64 hex secret>. Only the secret authenticates server-to-server invoice routes via X-Api-Key or Bearer. It is shown once. Legacy weak keys are revoked; provision replacements. Public keys do not grant secret privileges.
Refresh & logout
POST /auth/refresh consumes the current persisted refresh token and rotates it once. Serialize refresh calls: reuse revokes the entire family. POST /auth/logout revokes the server session; send the caller access Bearer as well as its cookie. Lost refresh responses require login, not blind retry. Access tokens stay in memory.