Login & Logout¶
Login¶
Public endpoint. No authentication required.
Request Body¶
| Field | Type | Required | Description |
|---|---|---|---|
username |
string | Yes | Account username or email address |
password |
string | Yes | Account password |
Response - Success (no 2FA)¶
HTTP/1.1 200 OK
Set-Cookie: access_token_cookie=<jwt>; HttpOnly; SameSite=Lax; Path=/
Set-Cookie: refresh_token_cookie=<jwt>; HttpOnly; SameSite=Lax; Path=/api/token-refresh
Set-Cookie: csrf_access_token=<token>; SameSite=Lax; Path=/
Set-Cookie: csrf_refresh_token=<token>; SameSite=Lax; Path=/api/token-refresh
Response - 2FA Required¶
When 2FA is enabled on the account, the login step returns a challenge instead of a full session:
Submit the TOTP code to /api/verify-2fa to complete login.
Response - First Sign-In¶
When the account has never been used:
Use session_token to set a new password via /api/first-signin.
Error - Invalid Credentials¶
HTTP/1.1 401 Unauthorized
{
"Message": "Invalid username or password.",
"Code": "User.InvalidCredentials"
}
Rate Limiting¶
After 3 consecutive failed login attempts, the account is temporarily locked with exponential backoff. Subsequent failures increase the lockout duration.
Logout¶
Authentication required.
CSRF header required: X-XSRF-TOKEN
Invalidates the current session by clearing authentication cookies server-side.
Example Request¶
POST /api/logout HTTP/1.1
Host: acme.knosc.com
Cookie: access_token_cookie=<jwt>
X-XSRF-TOKEN: <csrf-token>
Response¶
HTTP/1.1 200 OK
Set-Cookie: access_token_cookie=; Expires=Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: refresh_token_cookie=; Expires=Thu, 01 Jan 1970 00:00:00 GMT
Code Examples¶
curl - Login¶
curl -c cookies.txt -X POST https://acme.knosc.com/api/authenticate \
-H "Content-Type: application/json" \
-d '{"username": "jane.doe@acme.com", "password": "your-password"}'
curl - Logout¶
CSRF=$(grep csrf_access_token cookies.txt | awk '{print $NF}')
curl -b cookies.txt -X POST https://acme.knosc.com/api/logout \
-H "X-XSRF-TOKEN: $CSRF"
Python¶
import requests
BASE = "https://acme.knosc.com"
session = requests.Session()
# Login
r = session.post(f"{BASE}/api/authenticate", json={
"username": "jane.doe@acme.com",
"password": "your-password"
})
assert r.json().get("login"), "Login failed"
# ... use the session ...
# Logout
csrf = session.cookies.get("csrf_access_token")
session.post(f"{BASE}/api/logout", headers={"X-XSRF-TOKEN": csrf})