{"record":{"id":"c871311723ac93ac","repo":"BookStackApp/BookStack","slug":"an-e-parameter-on-the-provided-key-is-expected","errorCode":null,"errorMessage":"An \"e\" parameter on the provided key is expected","messagePattern":"An \"e\" parameter on the provided key is expected","errorType":"exception","errorClass":"OidcInvalidKeyException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcJwtSigningKey.php","lineNumber":73,"sourceCode":"     */\n    protected function loadFromJwkArray(array $jwk): void\n    {\n        // 'alg' is optional for a JWK, but we will still attempt to validate if\n        // it exists otherwise presume it will be compatible.\n        $alg = $jwk['alg'] ?? null;\n        if ($jwk['kty'] !== 'RSA' || !(is_null($alg) || $alg === 'RS256')) {\n            throw new OidcInvalidKeyException(\"Only RS256 keys are currently supported. Found key using {$alg}\");\n        }\n\n        // 'use' is optional for a JWK but we assume 'sig' where no value exists since that's what\n        // the OIDC discovery spec infers since 'sig' MUST be set if encryption keys come into play.\n        $use = $jwk['use'] ?? 'sig';\n        if ($use !== 'sig') {\n            throw new OidcInvalidKeyException(\"Only signature keys are currently supported. Found key for use {$jwk['use']}\");\n        }\n\n        if (empty($jwk['e'])) {\n            throw new OidcInvalidKeyException('An \"e\" parameter on the provided key is expected');\n        }\n\n        if (empty($jwk['n'])) {\n            throw new OidcInvalidKeyException('A \"n\" parameter on the provided key is expected');\n        }\n\n        $n = strtr($jwk['n'], '-_', '+/');\n\n        try {\n            $key = PublicKeyLoader::load([\n                'e' => new BigInteger(base64_decode($jwk['e']), 256),\n                'n' => new BigInteger(base64_decode($n), 256),\n            ]);\n        } catch (\\Exception $exception) {\n            throw new OidcInvalidKeyException(\"Failed to load key from JWK parameters with error: {$exception->getMessage()}\");\n        }\n\n        if (!$key instanceof RSA) {","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcJwtSigningKey.php#L55-L91","documentation":"Validation guard in OidcJwtSigningKey::loadFromJwkArray that rejects a JWK missing the RSA public exponent parameter 'e'. Fires when an OIDC discovery document supplies an RSA signing key whose 'e' field is absent, meaning the key cannot be used to verify JWT RS256 signatures.","triggerScenarios":"new OidcJwtSigningKey($jwkArray) with an RSA/sig JWK lacking 'e', or with 'e' set to an empty string/null.","commonSituations":"Hand-written or partially copied JWK fixtures; a JWKS publisher omitting 'e'; destructuring/extracting only 'n' and 'kty'; truncation when storing the JWK in config/DB.","solutions":["Include 'e' (typically 'AQAB') in the JWK array","Re-fetch the full JWK from the IdP's jwks_uri instead of copying partial data","Check persistence/config isn't truncating the stored JWK","For fixtures, add 'e' => 'AQAB'"],"exampleFix":"// before\n['kty' => 'RSA', 'n' => $n, 'use' => 'sig']\n// after\n['kty' => 'RSA', 'n' => $n, 'e' => 'AQAB', 'use' => 'sig']","handlingStrategy":"validation","validationCode":"if (empty($jwk['e'])) { throw new \\RuntimeException('JWK missing e parameter'); }","typeGuard":"function hasRsaPublicParams(array $jwk): bool { return !empty($jwk['e']) && !empty($jwk['n']); }","tryCatchPattern":"try { $key = new OidcJwtSigningKey($jwk); } catch (OidcInvalidKeyException $e) { if (str_contains($e->getMessage(), '\"e\" parameter')) { /* refetch full JWK */ } throw $e; }","preventionTips":["Always store/transmit the complete JWK (kty, n, e, use, kid)","Re-fetch JWKs from jwks_uri rather than hand-copying","Watch for config/DB fields truncating base64url values"],"tags":["oidc","jwk","rsa"],"backgroundTag":"invalid-jwk","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}