Skip to content

Commit ec3fe8a

Browse files
committed
JWT::EncodedToken#verify! to bundle signature and claim validation
1 parent b3701ef commit ec3fe8a

File tree

5 files changed

+62
-1
lines changed

5 files changed

+62
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
**Features:**
88

9+
- JWT::EncodedToken#verify! method that bundles signature and claim validation [#647](https://github.com/jwt/ruby-jwt/pull/647) ([@anakinj](https://github.com/anakinj))
910
- Your contribution here
1011

1112
**Fixes and enhancements:**

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,16 @@ encoded_token.payload # => { 'exp'=>1234, 'jti'=>'1234", 'sub'=>'my-subject' }
335335
encoded_token.header # {'kid'=>'hmac', 'alg'=>'HS256'}
336336
```
337337

338+
The `JWT::EncodedToken#verify!` method can be used to verify signature and claim verification in one go. The `exp` claim is verified by default.
339+
340+
```ruby
341+
encoded_token = JWT::EncodedToken.new(token.jwt)
342+
encoded_token.verify!(signature: {algorithm: 'HS256', key: "secret"})
343+
344+
encoded_token.payload # => { 'exp'=>1234, 'jti'=>'1234", 'sub'=>'my-subject' }
345+
encoded_token.header # {'kid'=>'hmac', 'alg'=>'HS256'}
346+
```
347+
338348
### Detached payload
339349

340350
The `::JWT::Token#detach_payload!` method can be use to detach the payload from the JWT.

lib/jwt/claims/verification_methods.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22

33
module JWT
44
module Claims
5-
# @api private
5+
# Provides methods to verify the claims of a token.
66
module VerificationMethods
7+
# Verifies the claims of the token.
8+
# @param options [Array<Symbol>, Hash] the claims to verify.
9+
# @raise [JWT::DecodeError] if the claims are invalid.
710
def verify_claims!(*options)
811
Verifier.verify!(self, *options)
912
end
1013

14+
# Returns the errors of the claims of the token.
15+
# @param options [Array<Symbol>, Hash] the claims to verify.
16+
# @return [Array<Symbol>] the errors of the claims.
1117
def claim_errors(*options)
1218
Verifier.errors(self, *options)
1319
end
1420

21+
# Returns whether the claims of the token are valid.
22+
# @param options [Array<Symbol>, Hash] the claims to verify.
23+
# @return [Boolean] whether the claims are valid.
1524
def valid_claims?(*options)
1625
claim_errors(*options).empty?
1726
end

lib/jwt/encoded_token.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ def signing_input
7272
[encoded_header, encoded_payload].join('.')
7373
end
7474

75+
# Verifies the token signature and claims.
76+
# By default it verifies the 'exp' claim.
77+
#
78+
# @example
79+
# encoded_token.verify!(signature: { algorithm: 'HS256', key: 'secret' }, claims: [:exp])
80+
#
81+
# @param signature [Hash] the parameters for signature verification (see {#verify_signature!}).
82+
# @param claims [Array<Symbol>, Hash] the claims to verify (see {#verify_claims!}).
83+
# @return [nil]
84+
# @raise [JWT::DecodeError] if the signature or claim verification fails.
85+
def verify!(signature:, claims: [:exp])
86+
verify_signature!(**signature)
87+
claims.is_a?(Array) ? verify_claims!(*claims) : verify_claims!(claims)
88+
nil
89+
end
90+
7591
# Verifies the signature of the JWT token.
7692
#
7793
# @param algorithm [String, Array<String>, Object, Array<Object>] the algorithm(s) to use for verification.

spec/jwt/encoded_token_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,31 @@
207207
end
208208
end
209209

210+
context '#verify!' do
211+
context 'when key is valid' do
212+
it 'does not raise' do
213+
expect(token.verify!(signature: { algorithm: 'HS256', key: 'secret' })).to eq(nil)
214+
end
215+
end
216+
217+
context 'when key is invalid' do
218+
it 'raises an error' do
219+
expect { token.verify!(signature: { algorithm: 'HS256', key: 'wrong' }) }.to raise_error(JWT::VerificationError, 'Signature verification failed')
220+
end
221+
end
222+
223+
context 'when claims are invalid' do
224+
let(:payload) { { 'pay' => 'load', exp: Time.now.to_i - 1000 } }
225+
226+
it 'raises an error' do
227+
expect do
228+
token.verify!(signature: { algorithm: 'HS256', key: 'secret' },
229+
claims: { exp: { leeway: 900 } })
230+
end.to raise_error(JWT::ExpiredSignature, 'Signature has expired')
231+
end
232+
end
233+
end
234+
210235
describe '#valid_claims?' do
211236
context 'exp claim' do
212237
let(:payload) { { 'exp' => Time.now.to_i - 10, 'pay' => 'load' } }

0 commit comments

Comments
 (0)