diff --git a/lib/jwt/default_decoder.rb b/lib/jwt/default_decoder.rb index 814a31e0..ea72eb1e 100644 --- a/lib/jwt/default_decoder.rb +++ b/lib/jwt/default_decoder.rb @@ -57,6 +57,10 @@ def self.define_decoder(verify:, **options) # rubocop:disable Metrics/MethodLeng decode_validators << Validators::IssuerClaimValidator.new(issuers: options[:iss]) end + if options[:verify_jti] + decode_validators << Validators::JwtIdClaimValidator.new(validator: options[:verify_jti]) + end + if Array(options[:required_claims]).any? decode_validators << Validators::RequiredClaimsValidator.new(required_claims: options[:required_claims]) end diff --git a/spec/jwt_spec.rb b/spec/jwt_spec.rb index 55fb8029..2185d3ea 100644 --- a/spec/jwt_spec.rb +++ b/spec/jwt_spec.rb @@ -765,14 +765,27 @@ let(:options) { { verify_iss: true, iss: 'expected_iss' } } subject(:decoded_token) { ::JWT.decode(token, 'secret', true, options) } - context 'when sub does not match' do + context 'when iss does not match' do let(:payload) { { 'iss' => 'not_expected_sub' } } - it 'raises InvalidSubError' do + it 'raises InvalidIssuerError' do expect { decoded_token }.to raise_error(JWT::InvalidIssuerError) end end end + describe 'jti claim validation' do + let(:token) { JWT.encode(payload, 'secret', 'HS256') } + let(:options) { { verify_jti: true } } + subject(:decoded_token) { ::JWT.decode(token, 'secret', true, options) } + + context 'when jti does not exist' do + let(:payload) { {} } + it 'raises InvalidJtiError' do + expect { decoded_token }.to raise_error(JWT::InvalidJtiError) + end + end + end + describe '::JWT.decode with x5c parameter' do let(:alg) { 'RS256' } let(:root_certificates) { [instance_double('OpenSSL::X509::Certificate')] }