@@ -174,6 +174,39 @@ def test_exchange_token_offline_token
174174 assert_equal ( expected_session , session )
175175 end
176176
177+ def test_exchange_token_uses_shop_from_session_token_dest_claim
178+ modify_context ( is_embedded : true , expiring_offline_access_tokens : false )
179+
180+ # Pass a different shop than what's in the JWT dest claim
181+ different_shop = "other-shop.myshopify.com"
182+
183+ # The request should go to the shop from the JWT dest claim, not the passed shop
184+ stub_request ( :post , "https://#{ @shop } /admin/oauth/access_token" )
185+ . with ( body : @non_expiring_offline_token_exchange_request )
186+ . to_return ( body : @offline_token_response . to_json , headers : { content_type : "application/json" } )
187+
188+ expected_session = ShopifyAPI ::Auth ::Session . new (
189+ id : "offline_#{ @shop } " ,
190+ shop : @shop ,
191+ access_token : @offline_token_response [ :access_token ] ,
192+ scope : @offline_token_response [ :scope ] ,
193+ is_online : false ,
194+ expires : nil ,
195+ shopify_session_id : @offline_token_response [ :session ] ,
196+ refresh_token : nil ,
197+ refresh_token_expires : nil ,
198+ )
199+
200+ session = ShopifyAPI ::Auth ::TokenExchange . exchange_token (
201+ shop : different_shop ,
202+ session_token : @session_token ,
203+ requested_token_type : ShopifyAPI ::Auth ::TokenExchange ::RequestedTokenType ::OFFLINE_ACCESS_TOKEN ,
204+ )
205+
206+ assert_equal ( expected_session , session )
207+ assert_equal ( @shop , session . shop )
208+ end
209+
177210 def test_exchange_token_expiring_offline_token
178211 modify_context ( is_embedded : true , expiring_offline_access_tokens : true )
179212 stub_request ( :post , "https://#{ @shop } /admin/oauth/access_token" )
@@ -229,6 +262,15 @@ def test_exchange_token_online_token
229262 assert_equal ( expected_session , session )
230263 end
231264
265+ def test_migrate_to_expiring_token_rejects_non_shopify_domain
266+ assert_raises ( ShopifyAPI ::Errors ::InvalidShopError ) do
267+ ShopifyAPI ::Auth ::TokenExchange . migrate_to_expiring_token (
268+ shop : "attacker.example" ,
269+ non_expiring_offline_token : "old-offline-token-123" ,
270+ )
271+ end
272+ end
273+
232274 def test_migrate_to_expiring_token_context_not_setup
233275 modify_context ( api_key : "" , api_secret_key : "" , host : "" )
234276
0 commit comments