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

  1. Include the full base64url-encoded modulus 'n' in the JWK
  2. Re-fetch the complete JWK from the IdP's jwks_uri
  3. Check that config/DB storage is not truncating the long 'n' value (column size, YAML line wrapping)
  4. 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

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


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