2.8 KiB
Personal API token scopes
Public API bearer authentication accepts only tokens owned by the exact App\Models\User model. The owner ID must be a positive, safely representable user ID, and the token must satisfy its existing expiration check. Both plaintext tokens and the existing {id}|{plaintext} request format remain supported; only the SHA-256 hash is looked up in the database.
The abilities column must contain a non-empty JSON array of non-empty strings. Null, malformed JSON, non-array JSON, empty arrays, non-string entries, and entries with surrounding whitespace are rejected. A valid "*" entry grants access to all existing bearer-protected endpoints. Other permissions match exactly: there is no tickets:* expansion, implicit read/write inheritance, or fallback to unrestricted access.
| Ability | Endpoint access |
|---|---|
tickets:read |
GET /api/tickets, GET /api/tickets/{id} |
tickets:write |
POST /api/tickets, POST /api/tickets/{id}/reply |
articles:write |
POST /api/articles/{slug}/comment |
radio:read |
GET /api/radio/points |
radio:write |
POST /api/radio/shouts |
badges:read |
Personal viewer data in GET /api/badges/leaderboard |
For example, ["tickets:read","radio:read"] allows reading the owner's tickets and radio points. It cannot create tickets, send replies, post article comments, or send radio shouts. Endpoint ownership checks and rate limits still apply after scope authorization.
Required-token endpoints return the existing generic 401 Unauthorized response when authorization fails. The badge leaderboard remains public: a denied bearer token receives the anonymous view, without personal viewer data. When an Authorization header is present, this endpoint does not use a session cookie to bypass a denied token. Session-only requests continue to personalize the leaderboard normally.
Compatibility and maintenance
Existing valid wildcard tokens remain compatible. The existing session-authenticated POST /api/tokens endpoint continues issuing ["*"]; this change does not add token-creation options or alter stored tokens. Legacy null, malformed, empty, differently cased model names, and unrelated model tokens are intentionally denied. Review and replace affected tokens with explicit intended scopes, or reissue through the existing token endpoint when full access is appropriate.
Every new bearer-authenticated endpoint must pass its required abilities to bearerUserId. Multiple required abilities use AND semantics. Omitting the requirements, or passing an empty list, requires a wildcard token rather than granting arbitrary scoped tokens access.
No plaintext token or stored hash is added to error responses or logs by these checks. The existing issuance endpoint returns plaintext once by design.