{"record":{"id":"128ece85179dcd77","repo":"lcobucci/jwt","slug":"token-signature-mismatch","errorCode":null,"errorMessage":"Token signature mismatch","messagePattern":"Token signature mismatch","errorType":"validation","errorClass":"ConstraintViolation","httpStatus":null,"severity":"error","filePath":"src/Validation/Constraint/SignedWith.php","lineNumber":29,"sourceCode":"\nfinal readonly class SignedWith implements SignedWithInterface\n{\n    public function __construct(private Signer $signer, private Signer\\Key $key)\n    {\n    }\n\n    public function assert(Token $token): void\n    {\n        if (! $token instanceof UnencryptedToken) {\n            throw ConstraintViolation::error('You should pass a plain token', $this);\n        }\n\n        if ($token->headers()->get('alg') !== $this->signer->algorithmId()) {\n            throw ConstraintViolation::error('Token signer mismatch', $this);\n        }\n\n        if (! $this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) {\n            throw ConstraintViolation::error('Token signature mismatch', $this);\n        }\n    }\n}\n","sourceCodeStart":11,"sourceCodeEnd":33,"githubUrl":"https://github.com/lcobucci/jwt/blob/375813049c24c7111bda8b6884c57b071ceb2fe7/src/Validation/Constraint/SignedWith.php#L11-L33","documentation":"SignedWith is a validation constraint that verifies a token's signature with a specific signer and key. It first checks that the token's 'alg' header matches the signer's algorithm, throwing 'Token signer mismatch' if not, then verifies the cryptographic signature. 'Token signature mismatch' means the alg header matched but the signature could not be verified with the given key.","triggerScenarios":"Calling Validator::assert($token, new SignedWith($signer, $key)) where the token's signature does not verify against the provided key — e.g. signed with a different private key, key rotated since issuance, or token payload was modified after signing.","commonSituations":"Using a verification key that differs from the signing key; testing tokens from another environment (staging token verified in prod); key rotation without token invalidation handling; tampered or truncated tokens copied incorrectly (extra whitespace/quotes); HS256 secret mismatch between services.","solutions":["Verify you pass the exact same key (or correct public key for asymmetric algorithms) used to sign the token","Confirm the token was not modified in transit — copy it whole without added whitespace or newlines","Check that signer algorithm matches how the token was actually signed (e.g. new Sha256() vs Sha384())","Log/compare the token's alg header and your signer's algorithmId() to rule out algorithm drift","Regenerate the token with the current key to confirm the verification path itself works"],"exampleFix":"// before\n$validator->assert($token, new SignedWith(new Sha256(), InMemory::plainText('wrong-secret')));\n// after\n$validator->assert($token, new SignedWith(new Sha256(), InMemory::plainText('the-same-secret-used-to-sign')));","handlingStrategy":"try-catch","validationCode":"if ($token instanceof UnencryptedToken && $token->headers()->get('alg') === 'HS256') {\n    // ensure your key material matches the one used at signing time before asserting\n}","typeGuard":"function isPlainSignedToken($token): bool { return $token instanceof UnencryptedToken && $token->signature()->hash() !== ''; }","tryCatchPattern":"try {\n    $validator->assert($token, new SignedWith(new Sha256(), $key));\n} catch (ConstraintViolation $e) {\n    // reject request / force re-authentication; log $e->getMessage()\n}","preventionTips":["Store signing keys in one shared secret manager consumed by both signer and verifier","Never log or truncate full tokens when copying between systems","Rotate keys with an overlap window (SignedWithOneInSet) instead of hard swaps","Pin signer algorithm on both sides and test with round-trip sign+verify in CI"],"tags":["jwt","signature","security","validation"],"backgroundTag":"jwt-signature-verification-failed","analyzedSha":"375813049c24c7111bda8b6884c57b071ceb2fe7","analyzedAt":"2026-09-14T11:12:28.004Z","contentChangedAt":"2026-09-14T11:12:28.004Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}