{"record":{"id":"9959f9198dc3b9d4","repo":"BookStackApp/BookStack","slug":"a-n-parameter-on-the-provided-key-is-expected","errorCode":null,"errorMessage":"A \"n\" parameter on the provided key is expected","messagePattern":"A \"n\" parameter on the provided key is expected","errorType":"exception","errorClass":"OidcInvalidKeyException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcJwtSigningKey.php","lineNumber":77,"sourceCode":"        // 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) {\n            throw new OidcInvalidKeyException('Key loaded from file path is not an RSA key as expected');\n        }\n\n        $this->key = $key->withPadding(RSA::SIGNATURE_PKCS1);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcJwtSigningKey.php#L59-L95","documentation":"Validation guard in OidcJwtSigningKey::loadFromJwkArray that rejects a JWK missing the RSA modulus parameter 'n'. Fires when the identity provider's discovery keys omit 'n', making the key incomplete and unusable for RS256 signature verification.","triggerScenarios":"new OidcJwtSigningKey($jwkArray) with a JWK missing 'n' or with an empty/null 'n' (after kty/use/e checks passed).","commonSituations":"Incomplete hand-written JWK fixtures; base64url payload stripped by config serialization; only 'kid'/'kty' copied from discovery; upstream JWKS bug omitting the modulus.","solutions":["Include the full base64url-encoded modulus 'n' in the JWK","Re-fetch the complete JWK from the IdP's jwks_uri","Check that config/DB storage is not truncating the long 'n' value (column size, YAML line wrapping)","For fixtures, generate a real keypair (openssl genrsa) and embed the actual n"],"exampleFix":"// before\n['kty' => 'RSA', 'e' => 'AQAB', 'use' => 'sig']\n// after\n['kty' => 'RSA', 'e' => 'AQAB', 'n' => '<base64url modulus from jwks_uri>', 'use' => 'sig']","handlingStrategy":"validation","validationCode":"if (empty($jwk['n'])) { throw new \\RuntimeException('JWK missing n 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(), '\"n\" parameter')) { /* refetch full JWK / fix storage truncation */ } throw $e; }","preventionTips":["Include the full base64url modulus when constructing JWKs","Ensure DB columns / config formats can hold the long modulus without truncation","Fetch complete JWKs from the IdP's jwks_uri at runtime or cache the full response"],"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"}