passbolt/passbolt_api · error · BadRequestException

JWT token is missing.

Error message

JWT token is missing.

What it means

BaseIdToken's constructor requires an `id_token` option that is a non-empty string; it throws BadRequestException('JWT token is missing.') otherwise. The id_token is the OIDC JWT returned by the identity provider and is the core input for all subsequent decoding and claim validation.

Solutions

  1. Verify the authorization request includes `openid` (and email/profile) scopes so the provider returns an id_token.
  2. Log/inspect the options array passed to the token constructor to confirm the `id_token` key exists and is a string.
  3. Check that the code reads id_token from the correct response field (token response vs userinfo).
  4. Confirm the provider actually issues id_tokens for the configured flow (some setups need explicit response_type/nonce handling).

Example fix

// before
new GoogleIdToken($provider, ['access_token' => $token]); // id_token missing
// after
new GoogleIdToken($provider, ['id_token' => $tokenResponse['id_token']]);
Defensive patterns

Strategy: validation

Validate before calling

$idToken = $tokenResponse['id_token'] ?? null;
if (!is_string($idToken) || $idToken === '') {
    throw new RuntimeException('No id_token in provider response; check openid scope');
}

Type guard

function hasIdToken(array $options): bool {
    return isset($options['id_token']) && is_string($options['id_token']) && $options['id_token'] !== '';
}

Try / catch

try {
    $token = new GoogleIdToken($provider, ['id_token' => $idToken]);
} catch (BadRequestException $e) {
    // id_token missing: ensure openid scope was requested and correct field extracted
}

Prevention

When it happens

Trigger: Instantiating a concrete BaseIdToken subclass (e.g. GoogleIdToken) with options where `id_token` is absent, null, an empty string, or a non-string value — typically when building the token object from an OAuth2 response that lacked id_token.

Common situations: Provider not configured to return id_token (missing openid scope); extracting the token from the wrong array key after a provider payload change; passing the access token instead of the id token under the wrong key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/OpenId/BaseIdToken.php:62

    /**
     * @var array
     */
    protected array $idTokenClaims;

    /**
     * @param array $options such as access_token, refresh_token and id_token
     * @param \Passbolt\Sso\Utility\Provider\AbstractOauth2Provider $provider provider
     * @throws \Cake\Http\Exception\InternalErrorException if keys to verify JWT cannot be fetched or validated
     * @throws \Cake\Http\Exception\BadRequestException if JWT doesn't validate
     */
    public function __construct(array $options, AbstractOauth2Provider $provider)
    {
        parent::__construct($options);

        $this->provider = $provider;

        if (empty($options['id_token']) || !is_string($options['id_token'])) {
            throw new BadRequestException(__('JWT token is missing.'));
        }
        $this->idToken = $options['id_token'];
        unset($this->values['id_token']);

        $keys = $provider->getJwtVerificationKeys();
        try {
            /**
             * To fix "Firebase\JWT\BeforeValidException: Cannot handle token prior" error.
             *
             * @link https://github.com/googleapis/google-api-php-client/issues/1630
             * @link https://stackoverflow.com/questions/53658600/uncaught-exception-firebase-jwt-beforevalidexception-with-message-cannot-hand
             */
            JWT::$leeway = Configure::read('passbolt.plugins.sso.security.jwtLeeway');

            $tokenClaims = (array)JWT::decode($this->idToken, $keys);
        } catch (Exception $exception) {
            if (Configure::read('passbolt.plugins.sso.debugEnabled')) {
                Log::error('idToken => ' . json_encode($this->idToken));

View on GitHub (pinned to 31c1bbc10f)