{"record":{"id":"869690c71220b084","repo":"BookStackApp/BookStack","slug":"could-not-parse-out-a-valid-prop-within-the-pro","errorCode":null,"errorMessage":"Could not parse out a valid {$prop} within the provided token","messagePattern":"Could not parse out a valid (.+?) within the provided token","errorType":"exception","errorClass":"OidcInvalidTokenException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcJwtWithClaims.php","lineNumber":106,"sourceCode":"    /**\n     * Replace the existing claim data of this token with that provided.\n     */\n    public function replaceClaims(array $claims): void\n    {\n        $this->payload = $claims;\n    }\n\n    /**\n     * Validate the structure of the given token and ensure we have the required pieces.\n     * As per https://datatracker.ietf.org/doc/html/rfc7519#section-7.2.\n     *\n     * @throws OidcInvalidTokenException\n     */\n    protected function validateTokenStructure(): void\n    {\n        foreach (['header', 'payload'] as $prop) {\n            if (empty($this->$prop)) {\n                throw new OidcInvalidTokenException(\"Could not parse out a valid {$prop} within the provided token\");\n            }\n        }\n\n        if (empty($this->signature)) {\n            throw new OidcInvalidTokenException('Could not parse out a valid signature within the provided token');\n        }\n    }\n\n    /**\n     * Validate the signature of the given token and ensure it validates against the provided key.\n     *\n     * @throws OidcInvalidTokenException\n     */\n    protected function validateTokenSignature(): void\n    {\n        if ($this->header['alg'] !== 'RS256') {\n            throw new OidcInvalidTokenException(\"Only RS256 signature validation is supported. Token reports using {$this->header['alg']}\");\n        }","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcJwtWithClaims.php#L88-L124","documentation":"OidcJwtWithClaims::validateTokenStructure splits the JWT into header, payload, and signature parts. If the header or payload section is empty after parsing (JSON decode produced nothing usable), it throws OidcInvalidTokenException naming the missing property. This catches tokens that are not structurally valid three-part JWTs.","triggerScenarios":"Calling validateCommonTokenDetails (via the OIDC validation flow) with a token string that is empty, malformed, has fewer than three dot-separated segments, or whose header/payload segments do not base64-decode into non-empty JSON.","commonSituations":"Truncated token sent by client; passing an opaque/access token instead of the OIDC id_token; token missing signature segment or containing extra whitespace/newlines; misconfigured callback passing the wrong request parameter.","solutions":["Verify the code passes the id_token, not an access or authorization code, into the validator","Check the token has three dot-separated segments before validation","Log the raw token (length/segments) to spot truncation by the client or proxy","Re-run the OIDC flow to get a fresh id_token"],"exampleFix":"// before\n$jwt->validate($token);\n\n// after\n$parts = explode('.', $token);\nif (count($parts) !== 3 || $parts[0] === '' || $parts[1] === '') {\n    throw new \\InvalidArgumentException('Malformed JWT: expected 3 non-empty segments');\n}\n$jwt->validate($token);","handlingStrategy":"validation","validationCode":"function isWellFormedJwt(string $token): bool {\n    $parts = explode('.', $token);\n    return count($parts) === 3\n        && $parts[0] !== '' && $parts[1] !== ''\n        && ($decoded = base64_decode(strtr($parts[0], '-_', '+/'), true)) !== false\n        && json_decode($decoded) !== null;\n}","typeGuard":"function looksLikeJwt(mixed $token): bool { return is_string($token) && substr_count($token, '.') === 2; }","tryCatchPattern":"try {\n    $jwt->validate($token);\n} catch (\\BookStack\\Access\\Oidc\\OidcInvalidTokenException $e) {\n    logger()->error('OIDC token rejected: ' . $e->getMessage());\n    // abort auth flow / redirect to login with error\n}","preventionTips":["Always pass the id_token (not access token) into validation","Assert token has 3 non-empty segments before validation","Check for transport-layer truncation (URL length limits, DB column sizes)"],"tags":["php","oidc","jwt","token-parsing","malformed-token"],"backgroundTag":"malformed-jwt","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}