passbolt/passbolt_api · error · BadRequestException

The authentication token id is invalid.

Error message

The authentication token id is invalid.

What it means

This BadRequestException is thrown by the account recovery request GET endpoint when the `tokenId` URL parameter is missing (null) or is not a valid UUID. The controller validates all route parameters up-front before delegating to the service layer, so a malformed token id never reaches the database lookup.

Solutions

  1. Verify the client calls the correct route order: /account-recovery/requests/{requestId}/{userId}/{tokenId}.
  2. Ensure the token id passed is the full UUID from the account recovery start response or email link.
  3. Check for null/empty query construction in the client SDK when the token is unavailable.
  4. Log the raw request URL server-side to confirm which segment is malformed.

Example fix

// before
await fetch(`/account-recovery/requests/${requestId}/${userId}`); // tokenId missing
// after
await fetch(`/account-recovery/requests/${requestId}/${userId}/${tokenId}`);
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!tokenId || !UUID_RE.test(tokenId)) throw new Error('token id must be a UUID');

Type guard

function isValidUuid(v) { return typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v); }

Try / catch

try { await api.getAccountRecoveryRequest(requestId, userId, tokenId); } catch (e) { if (e.code === 400 && /token id is invalid/.test(e.message)) { /* rebuild URL from stored token */ } else { throw e; } }

Prevention

When it happens

Trigger: GET /account-recovery/requests/<requestId>/<userId>/<tokenId> called with tokenId null, empty, or not a UUID (e.g. truncated token, placeholder value, or wrong URL segment ordering).

Common situations: Clients building the recovery URL manually and swapping the userId/tokenId segments; older browser extensions or scripts written for a previous route signature; copy-paste of the link missing the last segment.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/540752308f73c777. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/AccountRecovery/src/Controller/AccountRecoveryRequests/AccountRecoveryRequestsGetController.php:59

    }

    /**
     * Gets an account recovery request
     * Sends an email to the admins on suspect request
     *
     * @param string|null $requestId Request ID
     * @param string|null $userId User ID
     * @param string|null $tokenId Token ID
     * @return void
     * @throws \Cake\Http\Exception\BadRequestException if the data provided is not valid
     */
    public function get(?string $requestId, ?string $userId, ?string $tokenId): void
    {
        if (!isset($userId) || !Validation::uuid($userId)) {
            throw new BadRequestException(__('The user id is invalid.'));
        }
        if (!isset($tokenId) || !Validation::uuid($tokenId)) {
            throw new BadRequestException(__('The authentication token id is invalid.'));
        }
        if (!isset($requestId) || !Validation::uuid($requestId)) {
            throw new BadRequestException(__('The request id is invalid.'));
        }

        $ip = $this->getRequest()->clientIp();

        $service = new AccountRecoveryRequestGetService();
        $requestEntity = $service->getNotCompletedOrFail($requestId, $userId, $tokenId, $ip);
        $data = $service->decorateResults($requestEntity);

        $this->success(__('The operation was successful.'), $data);
    }
}

View on GitHub (pinned to 31c1bbc10f)