BookStackApp/BookStack · error · ApiAuthException
errors.api_bad_authorization_format
Error message
errors.api_bad_authorization_format
What it means
ApiTokenGuard::validateTokenHeaderValue throws ApiAuthException('errors.api_bad_authorization_format') when the Authorization header is present but malformed. BookStack API auth requires the header to start with 'Token ' followed by '<id>:<secret>'; the guard enforces the presence of the ':' separator and the 'Token ' prefix before attempting token lookup. It protects against parsing garbage or unsupported auth schemes (e.g. Bearer) downstream.
Source
Thrown at app/Api/ApiTokenGuard.php:110
throw new ApiAuthException(trans('errors.email_confirmation_awaiting'));
}
return $token->user;
}
/**
* Validate the format of the token header value string.
*
* @throws ApiAuthException
*/
protected function validateTokenHeaderValue(string $authToken): void
{
if (empty($authToken)) {
throw new ApiAuthException(trans('errors.api_no_authorization_found'));
}
if (!str_contains($authToken, ':') || !str_starts_with($authToken, 'Token ')) {
throw new ApiAuthException(trans('errors.api_bad_authorization_format'));
}
}
/**
* Validate the given secret against the given token and ensure the token
* currently has access to the instance API.
*
* @throws ApiAuthException
*/
protected function validateToken(?ApiToken $token, string $secret): void
{
if ($token === null) {
throw new ApiAuthException(trans('errors.api_user_token_not_found'));
}
if (!Hash::check($secret, $token->secret)) {
throw new ApiAuthException(trans('errors.api_incorrect_token_secret'));
}View on GitHub (pinned to 18f8469a1c)
Solutions
- Format the header exactly as 'Authorization: Token <token_id>:<token_secret>' using the id and secret from the user's API token page
- Verify there is a single space after 'Token' and a colon separating id and secret
- If using an HTTP client, confirm no middleware/proxy rewrites the Authorization header
- Regenerate the token if unsure of its components, since the secret is only shown once
Example fix
// before $client->withHeaders(['Authorization' => 'Bearer ' . $secret])->get($url); // after $client->withHeaders(['Authorization' => 'Token ' . $tokenId . ':' . $secret])->get($url);
Defensive patterns
Strategy: validation
Validate before calling
// PHP caller-side check before sending
$hdr = 'Token ' . $tokenId . ':' . $secret;
if (!str_starts_with($hdr, 'Token ') || substr_count($hdr, ':') !== 1) {
throw new InvalidArgumentException('Authorization header must be "Token <id>:<secret>"');
} Type guard
function isValidAuthHeader(string $header): bool {
return str_starts_with($header, 'Token ') && str_contains(substr($header, 6), ':');
} Try / catch
try {
$res = $client->get($url, ['headers' => ['Authorization' => $hdr]]);
} catch (ClientException $e) {
if ($e->getResponse()->getStatusCode() === 401) {
// rebuild header as 'Token <id>:<secret>' and retry once
}
throw $e;
} Prevention
- Always build the header as 'Token <id>:<secret>' from two separate config values
- Never mix Bearer/Basic schemes with BookStack API auth
- Trim whitespace from id and secret before composing the header
- Unit-test your auth-header builder once and reuse it everywhere
When it happens
Trigger: Sending an Authorization header without the 'Token ' prefix (e.g. 'Bearer abc123'); omitting the ':' separator between token id and secret (e.g. 'Token abc123xyz' with no id); sending an empty scheme or an entirely different credential format.
Common situations: Developers copying a Bearer-token pattern from other APIs; pasting only the token secret instead of '<id>:<secret>'; missing the space after 'Token'; clients that strip or mangle the Authorization header through a proxy.
Related errors
- errors.api_user_token_not_found
- Unauthorized
- errors.email_confirmation_awaiting
- errors.api_no_authorization_found
- errors.api_incorrect_token_secret
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/5344c73816da06a1.
Report an issue: GitHub.