Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow decode options to specify required claims #430

Merged
merged 3 commits into from Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -482,6 +482,14 @@ rescue JWT::InvalidIssuerError
end
```

### Required Claims

You can specify claims that must be present for decoding to be successful. JWT::MissingRequiredClaim will be raised if any are missing
```ruby
# Will raise a JWT::ExpiredSignature error if the 'exp' claim is absent
JWT.decode token, hmac_secret, true, { required_claims: ['exp'], algorithm: 'HS256' }
```

### JSON Web Key (JWK)

JWK is a JSON structure representing a cryptographic key. Currently only supports RSA public keys.
Expand Down
1 change: 1 addition & 0 deletions lib/jwt/decode.rb
Expand Up @@ -71,6 +71,7 @@ def find_key(&keyfinder)

def verify_claims
Verify.verify_claims(payload, @options)
Verify.verify_required_claims(payload, @options)
end

def validate_segment_count!
Expand Down
3 changes: 2 additions & 1 deletion lib/jwt/default_options.rb
Expand Up @@ -9,7 +9,8 @@ module DefaultOptions
verify_aud: false,
verify_sub: false,
leeway: 0,
algorithms: ['HS256']
algorithms: ['HS256'],
required_claims: []
}.freeze
end
end
1 change: 1 addition & 0 deletions lib/jwt/error.rb
Expand Up @@ -15,6 +15,7 @@ class InvalidAudError < DecodeError; end
class InvalidSubError < DecodeError; end
class InvalidJtiError < DecodeError; end
class InvalidPayload < DecodeError; end
class MissingRequiredClaim < DecodeError; end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JWT::MissingRequiredClaim has no descriptive comment

Read more about it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these error classes have a descriptive comment so I'm not sure I should add one.


class JWKError < DecodeError; end
end
9 changes: 8 additions & 1 deletion lib/jwt/verify.rb
Expand Up @@ -10,7 +10,7 @@ class Verify
}.freeze

class << self
%w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub].each do |method_name|
%w[verify_aud verify_expiration verify_iat verify_iss verify_jti verify_not_before verify_sub verify_required_claims].each do |method_name|
define_method method_name do |payload, options|
new(payload, options).send(method_name)
end
Expand Down Expand Up @@ -81,6 +81,13 @@ def verify_sub
raise(JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || '<none>'}") unless sub.to_s == options_sub.to_s
end

def verify_required_claims
return unless (options_required_claims = @options[:required_claims])
options_required_claims.each do |required_claim|
raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless @payload.include?(required_claim)
end
end

private

def global_leeway
Expand Down
14 changes: 14 additions & 0 deletions spec/integration/readme_examples_spec.rb
Expand Up @@ -226,6 +226,20 @@
end.not_to raise_error
end

it 'required_claims' do
payload = { data: 'test' }

token = JWT.encode payload, hmac_secret, 'HS256'

expect do
JWT.decode token, hmac_secret, true, required_claims: ['exp'], algorithm: 'HS256'
end.to raise_error(JWT::MissingRequiredClaim)

expect do
JWT.decode token, hmac_secret, true, required_claims: ['data'], algorithm: 'HS256'
end.not_to raise_error
end

it 'find_key' do
issuers = %w[My_Awesome_Company1 My_Awesome_Company2]
iss_payload = { data: 'data', iss: issuers.first }
Expand Down
13 changes: 13 additions & 0 deletions spec/jwt/verify_spec.rb
Expand Up @@ -248,4 +248,17 @@
end
end
end

context '.verify_required_claims(payload, options)' do
it 'must raise JWT::MissingRequiredClaim if a required claim is absent' do
expect do
described_class.verify_required_claims(base_payload, options.merge(required_claims: ['exp']))
end.to raise_error JWT::MissingRequiredClaim
end

it 'must verify the claims if all required claims are present' do
payload = base_payload.merge('exp' => (Time.now.to_i + 5), 'custom_claim' => true)
described_class.verify_required_claims(payload, options.merge(required_claims: ['exp', 'custom_claim']))
end
end
end