BookStackApp/BookStack · error · OidcInvalidKeyException
A "n" parameter on the provided key is expected
Error message
A "n" parameter on the provided key is expected
What it means
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.
Source
Thrown at app/Access/Oidc/OidcJwtSigningKey.php:77
// it exists otherwise presume it will be compatible.
$alg = $jwk['alg'] ?? null;
if ($jwk['kty'] !== 'RSA' || !(is_null($alg) || $alg === 'RS256')) {
throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}");
}
// 'use' is optional for a JWK but we assume 'sig' where no value exists since that's what
// the OIDC discovery spec infers since 'sig' MUST be set if encryption keys come into play.
$use = $jwk['use'] ?? 'sig';
if ($use !== 'sig') {
throw new OidcInvalidKeyException("Only signature keys are currently supported. Found key for use {$jwk['use']}");
}
if (empty($jwk['e'])) {
throw new OidcInvalidKeyException('An "e" parameter on the provided key is expected');
}
if (empty($jwk['n'])) {
throw new OidcInvalidKeyException('A "n" parameter on the provided key is expected');
}
$n = strtr($jwk['n'], '-_', '+/');
try {
$key = PublicKeyLoader::load([
'e' => new BigInteger(base64_decode($jwk['e']), 256),
'n' => new BigInteger(base64_decode($n), 256),
]);
} catch (\Exception $exception) {
throw new OidcInvalidKeyException("Failed to load key from JWK parameters with error: {$exception->getMessage()}");
}
if (!$key instanceof RSA) {
throw new OidcInvalidKeyException('Key loaded from file path is not an RSA key as expected');
}
$this->key = $key->withPadding(RSA::SIGNATURE_PKCS1);View on GitHub (pinned to 18f8469a1c)
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
Example fix
// before ['kty' => 'RSA', 'e' => 'AQAB', 'use' => 'sig'] // after ['kty' => 'RSA', 'e' => 'AQAB', 'n' => '<base64url modulus from jwks_uri>', 'use' => 'sig']
Defensive patterns
Strategy: validation
Validate before calling
if (empty($jwk['n'])) { throw new \RuntimeException('JWK missing n parameter'); } Type guard
function hasRsaPublicParams(array $jwk): bool { return !empty($jwk['e']) && !empty($jwk['n']); } Try / catch
try { $key = new OidcJwtSigningKey($jwk); } catch (OidcInvalidKeyException $e) { if (str_contains($e->getMessage(), '"n" parameter')) { /* refetch full JWK / fix storage truncation */ } throw $e; } Prevention
- 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
When it happens
Trigger: new OidcJwtSigningKey($jwkArray) with a JWK missing 'n' or with an empty/null 'n' (after kty/use/e checks passed).
Common situations: Incomplete hand-written JWK fixtures; base64url payload stripped by config serialization; only 'kid'/'kty' copied from discovery; upstream JWKS bug omitting the modulus.
Related errors
- An "e" parameter on the provided key is expected
- Failed to load key from JWK parameters with error: {$excepti
- Key loaded from file path is not an RSA key as expected
- Only RS256 keys are currently supported. Found key using {$a
- Only signature keys are currently supported. Found key for u
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/9959f9198dc3b9d4.
Report an issue: GitHub.