{"record":{"id":"746aaeb7f94ac5a3","repo":"BookStackApp/BookStack","slug":"only-signature-keys-are-currently-supported-found","errorCode":null,"errorMessage":"Only signature keys are currently supported. Found key for use {$jwk['use']}","messagePattern":"Only signature keys are currently supported\\. Found key for use (.+?)","errorType":"exception","errorClass":"OidcInvalidKeyException","httpStatus":null,"severity":"error","filePath":"app/Access/Oidc/OidcJwtSigningKey.php","lineNumber":69,"sourceCode":"    }\n\n    /**\n     * @throws OidcInvalidKeyException\n     */\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) {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Access/Oidc/OidcJwtSigningKey.php#L51-L87","documentation":"Beyond kty/alg, the JWK must be a signing key: the optional 'use' parameter, if present, must be 'sig'. Keys marked for encryption ('enc') are rejected because this class only builds signature verification keys. Absent 'use' defaults to 'sig' per OIDC discovery rules.","triggerScenarios":"new OidcJwtSigningKey($jwkArray) where $jwkArray['use'] is 'enc' (or any value other than 'sig').","commonSituations":"IdP publishes both signing and encryption keys in its JWKS and the code picks the encryption key; mis-copied JWK with use=enc; automated key-rotation script selecting keys without filtering on use.","solutions":["Filter the JWKS to keys with use === 'sig' (or no 'use' at all)","Pick the key whose kid matches the token header instead of the first key","If the IdP mislabels keys, correct its JWKS configuration","For test fixtures, set 'use' => 'sig' or remove 'use'"],"exampleFix":"// before\n$jwk = $jwks['keys'][0];\n// after\n$jwk = current(array_filter($jwks['keys'], fn($k) => ($k['use'] ?? 'sig') === 'sig' && $k['kty'] === 'RSA'));","handlingStrategy":"validation","validationCode":"if (($jwk['use'] ?? 'sig') !== 'sig') { throw new \\RuntimeException('JWK is not a signing key'); }","typeGuard":"function isSigJwk(array $jwk): bool { return ($jwk['use'] ?? 'sig') === 'sig'; }","tryCatchPattern":"try { $key = new OidcJwtSigningKey($jwk); } catch (OidcInvalidKeyException $e) { if (str_contains($e->getMessage(), 'signature keys')) { /* pick a use=sig key */ } throw $e; }","preventionTips":["Filter JWKS entries on use=sig (or missing use) before use","Prefer selecting the JWK by kid from the token header","Audit IdP JWKS for mislabeled encryption keys"],"tags":["oidc","jwk","key-usage"],"backgroundTag":"unsupported-key-type","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}