Skip to content

Commit

Permalink
Merge pull request #126 from yahooguntu/master
Browse files Browse the repository at this point in the history
Allow a proc to be passed for JTI verification
  • Loading branch information
excpt committed Feb 10, 2016
2 parents b85b30e + 0100ad6 commit d4fca40
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 6 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,6 @@ From [Oauth JSON Web Token 4.1.7. "jti" (JWT ID) Claim](https://tools.ietf.org/h
> The `jti` (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The `jti` claim can be used to prevent the JWT from being replayed. The `jti` value is a case-sensitive string. Use of this claim is OPTIONAL.
```ruby
# in order to use JTI you have to add iat
iat = Time.now.to_i
# Use the secret and iat to create a unique key per request to prevent replay attacks
jti_raw = [hmac_secret, iat].join(':').to_s
jti = Digest::MD5.hexdigest(jti_raw)
Expand All @@ -277,9 +275,10 @@ jti_payload = { :data => 'data', :iat => iat, :jti => jti }
token = JWT.encode jti_payload, hmac_secret, 'HS256'

begin
# Add jti and iat to the validation to check if the token has been manipulated
decoded_token = JWT.decode token, hmac_secret, true, { 'jti' => jti, :verify_jti => true, :algorithm => 'HS256' }
# Check if the JTI has already been used
# If :verify_jti is true, validation will pass if a JTI is present
#decoded_token = JWT.decode token, hmac_secret, true, { :verify_jti => true, :algorithm => 'HS256' }
# Alternatively, pass a proc with your own code to check if the JTI has already been used
decoded_token = JWT.decode token, hmac_secret, true, { :verify_jti => proc { |jti| my_validation_method(jti) }, :algorithm => 'HS256' }
rescue JWT::InvalidJtiError
# Handle invalid token, e.g. logout user or deny access
puts 'Error'
Expand Down
6 changes: 5 additions & 1 deletion lib/jwt/verify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ def self.verify_iat(payload, options)
end

def self.verify_jti(payload, _options)
fail(JWT::InvalidJtiError, 'Missing jti') if payload['jti'].to_s == ''
if _options[:verify_jti].class == Proc
fail(JWT::InvalidJtiError, 'Invalid jti') unless _options[:verify_jti].call(payload['jti'])
else
fail(JWT::InvalidJtiError, 'Missing jti') if payload['jti'].to_s == ''
end
end

def self.verify_aud(payload, options)
Expand Down
12 changes: 12 additions & 0 deletions spec/jwt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,18 @@
JWT.decode token, data[:secret], true, verify_jti: true
end.to_not raise_error
end

it 'false proc should raise JWT::InvalidJtiError' do
expect do
JWT.decode token, data[:secret], true, verify_jti: lambda { |jti| false }
end.to raise_error JWT::InvalidJtiError
end

it 'true proc should not raise JWT::InvalidJtiError' do
expect do
JWT.decode invalid_token, data[:secret], true, verify_jti: lambda { |jti| true }
end.to_not raise_error
end
end
end

Expand Down

0 comments on commit d4fca40

Please sign in to comment.