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

  1. Format the header exactly as 'Authorization: Token <token_id>:<token_secret>' using the id and secret from the user's API token page
  2. Verify there is a single space after 'Token' and a colon separating id and secret
  3. If using an HTTP client, confirm no middleware/proxy rewrites the Authorization header
  4. 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

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


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/5344c73816da06a1. Report an issue: GitHub.