diff --git a/docs/validating-tokens.md b/docs/validating-tokens.md index fb5190a9..6e3096c3 100644 --- a/docs/validating-tokens.md +++ b/docs/validating-tokens.md @@ -90,5 +90,6 @@ This library provides the following constraints: * `Lcobucci\JWT\Validation\Constraint\StrictValidAt`: verifies presence and validity of the claims `iat`, `nbf`, and `exp` (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\LooseValidAt`: verifies the claims `iat`, `nbf`, and `exp`, when present (supports leeway configuration) * `Lcobucci\JWT\Validation\Constraint\HasClaimWithValue`: verifies that a **custom claim** has the expected value (not recommended when comparing cryptographic hashes) +* `Lcobucci\JWT\Validation\Constraint\HasClaim`: verifies that a **custom claim** is present You may also create your [own validation constraints](extending-the-library.md#validation-constraints). diff --git a/src/Validation/Constraint/HasClaim.php b/src/Validation/Constraint/HasClaim.php new file mode 100644 index 00000000..c7b674ba --- /dev/null +++ b/src/Validation/Constraint/HasClaim.php @@ -0,0 +1,35 @@ +claims(); + + if (! $claims->has($this->claim)) { + throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this); + } + } +} diff --git a/tests/Validation/Constraint/HasClaimTest.php b/tests/Validation/Constraint/HasClaimTest.php new file mode 100644 index 00000000..df9ec51c --- /dev/null +++ b/tests/Validation/Constraint/HasClaimTest.php @@ -0,0 +1,79 @@ +expectException(CannotValidateARegisteredClaim::class); + $this->expectExceptionMessage( + 'The claim "' . $claim . '" is a registered claim, another constraint must be used to validate its value', + ); + + new HasClaim($claim); + } + + /** @return iterable */ + public static function registeredClaims(): iterable + { + foreach (Token\RegisteredClaims::ALL as $claim) { + yield $claim => [$claim]; + } + } + + /** @test */ + public function assertShouldRaiseExceptionWhenClaimIsNotSet(): void + { + $constraint = new HasClaim('claimId'); + + $this->expectException(ConstraintViolation::class); + $this->expectExceptionMessage('The token does not have the claim "claimId"'); + + $constraint->assert($this->buildToken()); + } + + /** @test */ + public function assertShouldRaiseExceptionWhenTokenIsNotAPlainToken(): void + { + $token = $this->createMock(Token::class); + $constraint = new HasClaim('claimId'); + + $this->expectException(ConstraintViolation::class); + $this->expectExceptionMessage('You should pass a plain token'); + + $constraint->assert($token); + } + + /** @test */ + public function assertShouldNotRaiseExceptionWhenClaimMatches(): void + { + $token = $this->buildToken(['claimId' => 'claimValue']); + $constraint = new HasClaim('claimId'); + + $constraint->assert($token); + $this->addToAssertionCount(1); + } +}