BookStackApp/BookStack · error · OidcInvalidKeyException

Only RS256 keys are currently supported. Found key using {$a

Error message

Only RS256 keys are currently supported. Found key using {$alg}

What it means

loadFromJwkArray validates that the JWK is an RSA signing key usable with RS256. It throws when kty is not 'RSA', or when an 'alg' is present and is anything other than 'RS256' (null alg is tolerated and presumed compatible).

Source

Thrown at app/Access/Oidc/OidcJwtSigningKey.php:62

        }

        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);
    }

    /**
     * @throws OidcInvalidKeyException
     */
    protected function loadFromJwkArray(array $jwk): void
    {
        // 'alg' is optional for a JWK, but we will still attempt to validate if
        // 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'], '-_', '+/');

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Select a JWK from the JWKS with kty=RSA (and alg RS256 or absent)
  2. Reconfigure the IdP to sign with RS256
  3. Filter discovery keys: only use entries where kty === 'RSA' and (alg is null or 'RS256')
  4. If you control the JWK fixture for tests, add/set 'kty' => 'RSA'

Example fix

// before
$jwk = $jwks['keys'][0]; // may be EC
// after
$jwk = current(array_filter($jwks['keys'], fn($k) => ($k['kty'] ?? null) === 'RSA' && in_array($k['alg'] ?? null, [null, 'RS256'], true)));
Defensive patterns

Strategy: validation

Validate before calling

if (($jwk['kty'] ?? null) !== 'RSA' || !in_array($jwk['alg'] ?? null, [null, 'RS256'], true)) { throw new \RuntimeException('JWK is not RS256/RSA'); }

Type guard

function isRs256Jwk(array $jwk): bool { return ($jwk['kty'] ?? null) === 'RSA' && in_array($jwk['alg'] ?? null, [null, 'RS256'], true); }

Try / catch

try { $key = new OidcJwtSigningKey($jwk); } catch (OidcInvalidKeyException $e) { if (str_contains($e->getMessage(), 'Only RS256')) { /* select another key or fix IdP alg */ } throw $e; }

Prevention

When it happens

Trigger: new OidcJwtSigningKey($jwkArray) where $jwkArray['kty'] !== 'RSA' (e.g. 'EC', 'OKP', 'oct') or $jwkArray['alg'] is 'ES256', 'RS384', 'RS512', etc.

Common situations: IdP configured for ES256/RS512 while the app only supports RS256; jwks_uri returns EC keys; picking the wrong key from a multi-key JWKS; missing 'kty' key in the JWK array.

Related errors


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