Skip to content

Commit

Permalink
Merge pull request #1312 from Shopify/add_leeway_for_jwt_nbf
Browse files Browse the repository at this point in the history
Use same leeway for `exp` and `nbf` when parsing JWT
  • Loading branch information
rachel-carvalho committed Apr 16, 2024
2 parents 7b09b25 + 0eb2306 commit c1163e0
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Note: For changes to the API, see https://shopify.dev/changelog?filter=api

## Unreleased
- [#1312](https://github.com/Shopify/shopify-api-ruby/pull/1312) Use same leeway for `exp` and `nbf` when parsing JWT

## 14.2.0
- [#1309](https://github.com/Shopify/shopify-api-ruby/pull/1309) Add `Session#copy_attributes_from` method
Expand Down
6 changes: 3 additions & 3 deletions lib/shopify_api/auth/jwt_payload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module Auth
class JwtPayload
extend T::Sig

JWT_EXPIRATION_LEEWAY = 10
JWT_LEEWAY = 10
JWT_EXPIRATION_LEEWAY = JWT_LEEWAY

sig { returns(String) }
attr_reader :iss, :dest, :aud, :sub, :jti, :sid
Expand Down Expand Up @@ -73,8 +74,7 @@ def ==(other)

sig { params(token: String, api_secret_key: String).returns(T::Hash[String, T.untyped]) }
def decode_token(token, api_secret_key)
JWT.decode(token, api_secret_key, true,
{ exp_leeway: JWT_EXPIRATION_LEEWAY, algorithm: "HS256" })[0]
JWT.decode(token, api_secret_key, true, leeway: JWT_LEEWAY, algorithm: "HS256")[0]
rescue JWT::DecodeError => err
raise ShopifyAPI::Errors::InvalidJwtTokenError, "Error decoding session token: #{err.message}"
end
Expand Down
40 changes: 39 additions & 1 deletion test/auth/jwt_payload_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_decode_jwt_payload_fails_with_expired_token

def test_decode_jwt_payload_fails_if_not_activated_yet
payload = @jwt_payload.dup
payload[:nbf] = (Time.now + 10).to_i
payload[:nbf] = (Time.now + 12).to_i
jwt_token = JWT.encode(payload, ShopifyAPI::Context.api_secret_key, "HS256")
assert_raises(ShopifyAPI::Errors::InvalidJwtTokenError) do
ShopifyAPI::Auth::JwtPayload.new(jwt_token)
Expand All @@ -92,6 +92,44 @@ def test_decode_jwt_payload_fails_with_invalid_api_key
ShopifyAPI::Auth::JwtPayload.new(jwt_token)
end
end

def test_decode_jwt_payload_succeeds_with_expiration_in_the_past_within_10s_leeway
payload = @jwt_payload.merge(exp: Time.now.to_i - 8)
jwt_token = JWT.encode(payload, ShopifyAPI::Context.api_secret_key, "HS256")

decoded = ShopifyAPI::Auth::JwtPayload.new(jwt_token)

assert_equal(payload, {
iss: decoded.iss,
dest: decoded.dest,
aud: decoded.aud,
sub: decoded.sub,
exp: decoded.exp,
nbf: decoded.nbf,
iat: decoded.iat,
jti: decoded.jti,
sid: decoded.sid,
})
end

def test_decode_jwt_payload_succeeds_with_not_before_in_the_future_within_10s_leeway
payload = @jwt_payload.merge(nbf: Time.now.to_i + 8)
jwt_token = JWT.encode(payload, ShopifyAPI::Context.api_secret_key, "HS256")

decoded = ShopifyAPI::Auth::JwtPayload.new(jwt_token)

assert_equal(payload, {
iss: decoded.iss,
dest: decoded.dest,
aud: decoded.aud,
sub: decoded.sub,
exp: decoded.exp,
nbf: decoded.nbf,
iat: decoded.iat,
jti: decoded.jti,
sid: decoded.sid,
})
end
end
end
end

0 comments on commit c1163e0

Please sign in to comment.