Files
EpicNext-Cms/docs/operations/personal-tokens/README.md
T
Simo 8abfe352ef
CI / check (push) Successful in 3m15s
CI / deploy (push) Successful in 1m19s
CI / publish-container (push) Successful in 48s
fix(security): authorize site uploads and harden tokens, media and request identity
2026-09-13 19:24:43 +02:00

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.