Add API token allowlist, docs, UI and tests

Introduce API token allowlist support and documentation. Adds a new backend docs page for API tokens and updates TABLEOFCONTENTS. Implements API token constants and a compiled matcher (isEndpointAllowed) with support for single-segment :placeholders and an isWrite flag. Split getCurrentUser into a JWT-only helper and added getCurrentUserAsync to recognize rmab_ API tokens; updated the audiobooks search route to use getCurrentUserAsync. Update API docs UI (EndpointCard and api-docs page) to surface Write badges and disable "Try it" for mutating endpoints, and add a profile warning in ApiTokensSection. Add tests for the allowlist matcher and middleware, and adjust existing route tests/mocks accordingly.
This commit is contained in:
kikootwo
2026-05-16 14:17:49 -04:00
parent e39e44ee44
commit 6ec53ff7e3
11 changed files with 417 additions and 39 deletions
+20 -1
View File
@@ -242,7 +242,9 @@ export async function requireAdmin(
}
/**
* Helper: Get current user from request (for use in API routes)
* Helper: Get current user from request (for use in API routes).
* JWT-only — does NOT recognize API tokens. Use `getCurrentUserAsync` if
* the caller should also accept `rmab_`-prefixed API tokens.
*/
export function getCurrentUser(request: NextRequest): TokenPayload | null {
const token = extractToken(request);
@@ -250,6 +252,23 @@ export function getCurrentUser(request: NextRequest): TokenPayload | null {
return verifyAccessToken(token);
}
/**
* Helper: Get current user from request, recognizing BOTH JWT sessions and
* API tokens (`rmab_` prefix). Returns the same `TokenPayload` shape in both
* cases so callers don't need to branch on auth type.
*
* Use this in routes that are open to optional auth but should still enrich
* responses with per-user context when called by an API token holder.
*/
export async function getCurrentUserAsync(request: NextRequest): Promise<TokenPayload | null> {
const token = extractToken(request);
if (!token) return null;
if (token.startsWith(API_TOKEN_PREFIX)) {
return authenticateApiToken(token);
}
return verifyAccessToken(token);
}
/**
* Helper: Check if user is admin
*/