From 0ffe471eb61e82f33933e191f1cf6e3b79f5ab2a Mon Sep 17 00:00:00 2001 From: Rachel Carvalho Date: Tue, 16 Apr 2024 12:32:13 -0400 Subject: [PATCH 1/3] use same leeway for `exp` and `nbf` --- lib/shopify_api/auth/jwt_payload.rb | 3 +-- test/auth/jwt_payload_test.rb | 40 ++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/shopify_api/auth/jwt_payload.rb b/lib/shopify_api/auth/jwt_payload.rb index e61b92bb4..9a81730b2 100644 --- a/lib/shopify_api/auth/jwt_payload.rb +++ b/lib/shopify_api/auth/jwt_payload.rb @@ -73,8 +73,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_EXPIRATION_LEEWAY, algorithm: "HS256")[0] rescue JWT::DecodeError => err raise ShopifyAPI::Errors::InvalidJwtTokenError, "Error decoding session token: #{err.message}" end diff --git a/test/auth/jwt_payload_test.rb b/test/auth/jwt_payload_test.rb index 7ca6bdd62..8bbe8a0ac 100644 --- a/test/auth/jwt_payload_test.rb +++ b/test/auth/jwt_payload_test.rb @@ -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) @@ -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 From 9c481e55fe3815ac3db365148a4f1e9229638722 Mon Sep 17 00:00:00 2001 From: Rachel Carvalho Date: Tue, 16 Apr 2024 12:37:59 -0400 Subject: [PATCH 2/3] add changelog line --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5872c10a5..3e4e13b4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 From 0eb2306ba57e2d4eeb388fdfebec9e2107247d28 Mon Sep 17 00:00:00 2001 From: Rachel Carvalho Date: Tue, 16 Apr 2024 13:20:27 -0400 Subject: [PATCH 3/3] use JWT_LEEWAY constant for JWT leeway param --- lib/shopify_api/auth/jwt_payload.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/shopify_api/auth/jwt_payload.rb b/lib/shopify_api/auth/jwt_payload.rb index 9a81730b2..bd13326cd 100644 --- a/lib/shopify_api/auth/jwt_payload.rb +++ b/lib/shopify_api/auth/jwt_payload.rb @@ -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 @@ -73,7 +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, 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