diff --git a/CHANGELOG.md b/CHANGELOG.md index 619b7ee2..6d17c141 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 +- [#1481](https://github.com/Shopify/shopify-api-ruby/pull/1481) `ShopifyAPI::Auth::TokenExchange.exchange_token` now raises `ShopifyAPI::Errors::InvalidJwtTokenError` when token exchange rejects the session token with `invalid_identity_session`, matching the existing `invalid_subject_token` handling. - [#1475](https://github.com/Shopify/shopify-api-ruby/pull/1475) Add an optional `client_assertion:` argument to `ShopifyAPI::Auth::ClientCredentials.client_credentials`. When supplied, the token request authenticates with a JWT client assertion and sends no client secret. Omitting it, or passing `nil`, keeps the existing client-secret behavior. See the [OAuth documentation](docs/usage/oauth.md#client-assertion-authentication). - [#1475](https://github.com/Shopify/shopify-api-ruby/pull/1475) Add `ShopifyAPI::Auth::ClientAssertion.create`, an optional helper that signs a client assertion with an `RS256` (RSA, 2048-bit minimum) or `ES256` (EC P-256) private key your app owns. `client_id` defaults to `ShopifyAPI::Context.api_key`, the only value the helper reads from the context, and it never generates, imports, stores, or rotates keys. - [#1475](https://github.com/Shopify/shopify-api-ruby/pull/1475) Add `ShopifyAPI::Errors::InvalidClientAssertionError`, raised for a blank or non-`String` assertion, for an assertion with surrounding whitespace, and for invalid signer input. diff --git a/lib/shopify_api/auth/token_exchange.rb b/lib/shopify_api/auth/token_exchange.rb index 5406a6c7..1ebb20fc 100644 --- a/lib/shopify_api/auth/token_exchange.rb +++ b/lib/shopify_api/auth/token_exchange.rb @@ -73,7 +73,8 @@ def exchange_token(session_token:, requested_token_type:, shop: nil) ), ) rescue ShopifyAPI::Errors::HttpResponseError => error - if error.code == 400 && error.response.body["error"] == "invalid_subject_token" + if error.code == 400 && + ["invalid_subject_token", "invalid_identity_session"].include?(error.response.body["error"]) raise ShopifyAPI::Errors::InvalidJwtTokenError, "Session token was rejected by token exchange" end diff --git a/test/auth/token_exchange_test.rb b/test/auth/token_exchange_test.rb index 239a3620..ebb2c50a 100644 --- a/test/auth/token_exchange_test.rb +++ b/test/auth/token_exchange_test.rb @@ -143,6 +143,24 @@ def test_exchange_token_rejected_session_token end end + def test_exchange_token_rejected_identity_session + modify_context(is_embedded: true) + stub_request(:post, "https://#{@shop}/admin/oauth/access_token") + .with(body: @non_expiring_offline_token_exchange_request) + .to_return( + status: 400, + body: { error: "invalid_identity_session" }.to_json, + headers: { content_type: "application/json" }, + ) + + assert_raises(ShopifyAPI::Errors::InvalidJwtTokenError) do + ShopifyAPI::Auth::TokenExchange.exchange_token( + session_token: @session_token, + requested_token_type: ShopifyAPI::Auth::TokenExchange::RequestedTokenType::OFFLINE_ACCESS_TOKEN, + ) + end + end + def test_exchange_token_deprecates_shop_argument modify_context(is_embedded: true, expiring_offline_access_tokens: false) ShopifyAPI::Logger.expects(:deprecated).with(