{"record":{"id":"8e0e794a7396de43","repo":"jwtk/jjwt","slug":"cannot-verify-jws-signature-unable-to-locate-sign","errorCode":null,"errorMessage":"Cannot verify JWS signature: unable to locate signature verification key for JWS with header: ${jwsHeader}","messagePattern":"Cannot verify JWS signature: unable to locate signature verification key for JWS with header: (.+?)","errorType":"exception","errorClass":"UnsupportedJwtException","httpStatus":null,"severity":"error","filePath":"impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java","lineNumber":293,"sourceCode":"        try {\n            algorithm = (SecureDigestAlgorithm<?, Key>) sigAlgs.apply(jwsHeader);\n        } catch (UnsupportedJwtException e) {\n            //For backwards compatibility.  TODO: remove this try/catch block for 1.0 and let UnsupportedJwtException propagate\n            String msg = \"Unsupported signature algorithm '\" + alg + \"': \" + e.getMessage();\n            throw new SignatureException(msg, e);\n        }\n        Assert.stateNotNull(algorithm, \"JWS Signature Algorithm cannot be null.\");\n\n        //digitally signed, let's assert the signature:\n        Key key;\n        if (claims != null) {\n            key = resolver.resolveSigningKey(jwsHeader, claims);\n        } else {\n            key = resolver.resolveSigningKey(jwsHeader, payload.getBytes());\n        }\n        if (key == null) {\n            String msg = \"Cannot verify JWS signature: unable to locate signature verification key for JWS with header: \" + jwsHeader;\n            throw new UnsupportedJwtException(msg);\n        }\n        Provider provider = ProviderKey.getProvider(key, this.provider); // extract if necessary\n        key = ProviderKey.getKey(key); // unwrap if necessary, MUST be called after ProviderKey.getProvider\n        Assert.stateNotNull(key, \"ProviderKey cannot be null.\"); //ProviderKey impl doesn't allow null\n        if (key instanceof PrivateKey) {\n            throw new InvalidKeyException(PRIV_KEY_VERIFY_MSG);\n        }\n\n        final byte[] signature = decode(tokenized.getDigest(), \"JWS signature\");\n\n        //re-create the jwt part without the signature.  This is what is needed for signature verification:\n        InputStream payloadStream = null;\n        InputStream verificationInput;\n        if (jwsHeader.isPayloadEncoded()) {\n            int len = tokenized.getProtected().length() + 1 + tokenized.getPayload().length();\n            CharBuffer cb = CharBuffer.allocate(len);\n            cb.put(Strings.wrap(tokenized.getProtected()));\n            cb.put(SEPARATOR_CHAR);","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/jwtk/jjwt/blob/fb71496164c71442d08adec4571d9616ed5e1b8d/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java#L275-L311","documentation":"verifySignature() asks the configured SigningKeyResolver (or parser key configuration) for the verification key for the JWS header/payload/claims. If the resolver returns null, the parser cannot verify the signature and throws UnsupportedJwtException with this message.","triggerScenarios":"Using .keyLocator(...) or a custom SigningKeyResolver whose resolveSigningKey(header, claims/payload) returns null (e.g. unmatched kid in a JWKS lookup, unsupported key type in the resolver's switch).","commonSituations":"Multi-tenant JWKS key location where the token's 'kid' is not in the key set yet (rotation lag); resolver logic that returns null instead of throwing for unknown kids; parser configured without any key at all for resolver-based flows.","solutions":["Fix the SigningKeyResolver/keyLocator to return the correct key for the header (match on kid/issuer) or throw a descriptive exception instead of returning null","Ensure the token's kid exists in your JWKS/key store — refresh keys on rotation","Verify the resolver handles all expected key types/headers before returning"],"exampleFix":"// before\npublic Key resolveSigningKey(JwsHeader h, Claims c) {\n    return keys.get(h.getKeyId()); // may be null\n}\n// after\npublic Key resolveSigningKey(JwsHeader h, Claims c) {\n    Key k = keys.get(h.getKeyId());\n    if (k == null) throw new SignatureException(\"Unknown kid: \" + h.getKeyId());\n    return k;\n}","handlingStrategy":"validation","validationCode":"Key key = keys.get(header.getKeyId());\nif (key == null) {\n    throw new SignatureException(\"No verification key for kid: \" + header.getKeyId());\n}","typeGuard":null,"tryCatchPattern":"try {\n    return parser.build().parseSignedClaims(token);\n} catch (UnsupportedJwtException e) {\n    if (e.getMessage().contains(\"unable to locate signature verification key\")) {\n        keyProvider.refresh(); // JWKS rotation\n    }\n    throw new UnauthorizedException(e);\n}","preventionTips":["Never return null from SigningKeyResolver — throw instead","Refresh JWKS on unknown kid before rejecting","Cover all key types in resolver branching logic"],"tags":["jwt","signature","key-resolution"],"backgroundTag":"missing-credentials","analyzedSha":"fb71496164c71442d08adec4571d9616ed5e1b8d","analyzedAt":"2026-09-09T00:33:09.982Z","contentChangedAt":"2026-09-09T00:33:09.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}