BookStackApp/BookStack · error · OidcInvalidTokenException

Subject value provided in the userinfo endpoint does not mat

Error message

Subject value provided in the userinfo endpoint does not match the provided ID token value

What it means

OIDC spec v1.0 §5.3.2 requires the UserInfo response 'sub' to exactly equal the ID token's 'sub'. OidcUserinfoResponse::validate() throws this OidcInvalidTokenException when the two subject values differ, and BookStack must refuse to use the userinfo data.

Source

Thrown at app/Access/Oidc/OidcUserinfoResponse.php:46

     * @throws OidcInvalidTokenException
     */
    public function validate(string $idTokenSub, string $clientId): bool
    {
        if (!is_null($this->jwt)) {
            $this->jwt->validateCommonTokenDetails($clientId);
        }

        $sub = $this->getClaim('sub');

        // Spec: v1.0 5.3.2: The sub (subject) Claim MUST always be returned in the UserInfo Response.
        if (!is_string($sub) || empty($sub)) {
            throw new OidcInvalidTokenException("No valid subject value found in userinfo data");
        }

        // Spec: v1.0 5.3.2: The sub Claim in the UserInfo Response MUST be verified to exactly match the sub Claim in the ID Token;
        // if they do not match, the UserInfo Response values MUST NOT be used.
        if ($idTokenSub !== $sub) {
            throw new OidcInvalidTokenException("Subject value provided in the userinfo endpoint does not match the provided ID token value");
        }

        // Spec v1.0 5.3.4 Defines the following:
        // Verify that the OP that responded was the intended OP through a TLS server certificate check, per RFC 6125 [RFC6125].
          // This is effectively done as part of the HTTP request we're making through CURLOPT_SSL_VERIFYHOST on the request.
        // If the Client has provided a userinfo_encrypted_response_alg parameter during Registration, decrypt the UserInfo Response using the keys specified during Registration.
          // We don't currently support JWT encryption for OIDC
        // If the response was signed, the Client SHOULD validate the signature according to JWS [JWS].
          // This is done as part of the validateCommonClaims above.

        return true;
    }

    public function getClaim(string $claim): mixed
    {
        return $this->claims[$claim] ?? null;
    }

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. In the IdP client settings, set subject identifier type to 'public' for both ID token and userinfo
  2. If pairwise subjects are required, ensure both tokens derive the same pairwise value for the client_id
  3. Clear any caches/proxies between BookStack and the IdP that could return stale userinfo
  4. Confirm the access token used for userinfo corresponds to the same ID token (no token mixing in your config)
  5. Update the IdP version — some providers had bugs issuing inconsistent subs

Example fix

// before (Keycloak client)
"subjectType": "pairwise"
// after
"subjectType": "public"
Defensive patterns

Strategy: validation

Validate before calling

// Compare subs before login:
$idClaims = json_decode(base64_decode(explode('.', $idToken)[1]), true);
$ui = json_decode($userinfoBody, true);
if (($idClaims['sub'] ?? null) !== ($ui['sub'] ?? null)) {
    // mismatch: switch IdP client subject type to public or drop userinfo
}

Try / catch

try {
    auth()->attemptOidcLogin();
} catch (BookStack\Access\Oidc\OidcException $e) {
    if (str_contains($e->getMessage(), 'does not match the provided ID token')) {
        abort(502, 'Userinfo sub does not match ID token sub — set subject type to public at the IdP');
    }
    throw $e;
}

Prevention

When it happens

Trigger: validate() compares $idTokenSub !== $sub (strict string compare) from getUserDetailsFromToken and they differ — different subject identifiers issued per-client (pairwise subjects), or the userinfo endpoint served data for a different user/session.

Common situations: Keycloak/Auth0/Authentik configured with pairwise subject identifiers where ID token and userinfo use different algorithms, multi-tenant IdPs issuing per-client subs, a caching layer serving a stale userinfo response for another user, or the access token being exchanged/mixed between sessions.

Related errors


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