You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: BREAKING_CHANGES_FOR_V15.md
+98-3Lines changed: 98 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,99 @@
1
1
# Breaking change notice for version 15.0.0
2
2
3
+
## Removal of positional `storefront_access_token` parameter from Storefront GraphQL Client
4
+
5
+
The `ShopifyAPI::Clients::Graphql::Storefront` class no longer accepts the public Storefront access token as a positional parameter. You must now use the named parameters `private_token:` or `public_token:` instead.
6
+
7
+
This parameter was deprecated in [PR #1302](https://github.com/Shopify/shopify-api-ruby/pull/1302) (v14.1.0).
8
+
9
+
### Previous implementation (deprecated in v14.1.0)
For more information on private vs public Storefront access tokens, see [Shopify's authentication documentation](https://shopify.dev/docs/api/usage/authentication#getting-started-with-private-access).
37
+
## Removal of `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants
38
+
39
+
The `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants have been removed to prevent semantic versioning (semver) breaking changes. Previously, these constants would automatically update every quarter when new API versions were released, causing unintended breaking changes for apps.
api_version ="2025-07"# Explicitly specify the version you want to use
53
+
```
54
+
55
+
**In your Context.setup:**
56
+
57
+
The `api_version` parameter has always been required in `Context.setup`, so most apps should not be affected. However, you must now explicitly specify which API version you want to use:
58
+
59
+
```ruby
60
+
# Before (v14 and earlier)
61
+
ShopifyAPI::Context.setup(
62
+
api_key:"<api-key>",
63
+
api_secret_key:"<api-secret-key>",
64
+
host:"<https://application-host-name.com>",
65
+
scope:"read_orders,read_products,etc",
66
+
is_embedded:true,
67
+
api_version:ShopifyAPI::LATEST_SUPPORTED_ADMIN_VERSION, # This constant no longer exists
68
+
is_private:false,
69
+
)
70
+
71
+
# After (v15+)
72
+
ShopifyAPI::Context.setup(
73
+
api_key:"<api-key>",
74
+
api_secret_key:"<api-secret-key>",
75
+
host:"<https://application-host-name.com>",
76
+
scope:"read_orders,read_products,etc",
77
+
is_embedded:true,
78
+
api_version:"2025-07", # Explicitly specify the version
79
+
is_private:false,
80
+
)
81
+
```
82
+
83
+
**Finding the right API version:**
84
+
85
+
You can see all supported API versions by referencing:
By requiring explicit version specification, apps can:
93
+
- Control when they upgrade to new API versions
94
+
- Test thoroughly before upgrading
95
+
- Avoid unexpected breaking changes from automatic version updates
96
+
3
97
## Removal of `ShopifyAPI::Webhooks::Handler`
4
98
5
99
The `ShopifyAPI::Webhooks::Handler` class has been removed in favor of `ShopifyAPI::Webhooks::WebhookHandler`. The `ShopifyAPI::Webhooks::WebhookHandler` class is now the recommended way to handle webhooks.
@@ -8,7 +102,8 @@ Make a module or class that includes or extends `ShopifyAPI::Webhooks::WebhookHa
8
102
9
103
In v14, adding new fields to the callback would become a breaking change. To make this code more flexible, handlers will now receive an object that can be typed and extended.
10
104
11
-
`data` will have the following keys
105
+
`data` will have the following keys:
106
+
12
107
-`topic`, `String` - The topic of the webhook
13
108
-`shop`, `String` - The shop domain of the webhook
14
109
-`body`, `T::Hash[String, T.untyped]`- The body of the webhook
The minimum required Ruby version has been updated from 3.0 to 3.2.
6
+
7
+
### Why this change?
8
+
9
+
Ruby 3.0 and 3.1 have reached End of Life (EOL).
10
+
11
+
### Migration Guide
12
+
13
+
If you're currently using Ruby 3.0 or 3.1, you'll need to upgrade to Ruby 3.2 or higher before upgrading to shopify-api-ruby v16.0.0.
14
+
15
+
**Note:** Ruby 3.2+ includes performance improvements and new features. Most applications should not require code changes beyond updating the Ruby version itself.
16
+
## Removal of `Session#serialize` and `Session.deserialize` methods
17
+
18
+
The `Session#serialize` and `Session.deserialize` methods have been removed due to a security vulnerability. The `deserialize` method used `Oj.load` without safe mode, which allows instantiation of arbitrary Ruby objects.
19
+
20
+
These methods were originally created for session persistence when the library handled session storage. After session storage was deprecated in v12.3.0, applications became responsible for their own session persistence, making these methods unnecessary for their original purpose.
21
+
22
+
### Why this change?
23
+
24
+
**No impact on most applications:** The `shopify_app gem` stores individual session attributes in database columns and reconstructs sessions using `Session.new()`, which is the recommended pattern.
25
+
26
+
## Migration Guide
27
+
28
+
If your application was using `Session#serialize` and `Session.deserialize` for session persistence, you'll need to refactor to store individual session attributes and reconstruct sessions using `Session.new()`.
Store individual session attributes and reconstruct using `Session.new()`:
52
+
53
+
## Reference: shopify_app gem implementation
54
+
55
+
The [shopify_app gem](https://github.com/Shopify/shopify_app) provides a reference implementation of session storage that follows these best practices:
Copy file name to clipboardExpand all lines: CHANGELOG.md
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,18 @@
2
2
3
3
Note: For changes to the API, see https://shopify.dev/changelog?filter=api
4
4
## Unreleased
5
+
- ⚠️ [Breaking] Minimum required Ruby version is now 3.2. Ruby 3.0 and 3.1 are no longer supported.
6
+
- ⚠️ [Breaking] Removed `Session#serialize` and `Session.deserialize` methods due to security concerns (RCE vulnerability via `Oj.load`). These methods were not used internally by the library. If your application relies on session serialization, use `Session.new()` to reconstruct sessions from stored attributes instead.
7
+
8
+
- Add support for expiring offline access tokens with refresh tokens. See [OAuth documentation](docs/usage/oauth.md#expiring-offline-access-tokens) for details.
9
+
- Add `ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token` method to migrate existing non-expiring offline tokens to expiring tokens. See [migration documentation](docs/usage/oauth.md#migrating-non-expiring-tokens-to-expiring-tokens) for details.
10
+
11
+
### 15.0.0
12
+
13
+
- ⚠️ [Breaking] Removed deprecated `ShopifyAPI::Webhooks::Handler` interface. Apps must migrate to `ShopifyAPI::Webhooks::WebhookHandler` which provides `webhook_id` and `api_version` in addition to `topic`, `shop`, and `body`. See [BREAKING_CHANGES_FOR_V15.md](BREAKING_CHANGES_FOR_V15.md) for migration guide.
14
+
- Add support for 2025-10 API version
15
+
- Updated `LATEST_SUPPORTED_ADMIN_VERSION` to `2025-10`
16
+
-[#1411](https://github.com/Shopify/shopify-api-ruby/pull/1411) Remove `LATEST_SUPPORTED_ADMIN_VERSION` and `RELEASE_CANDIDATE_ADMIN_VERSION` constants to prevent semver violations. Developers must now explicitly specify API versions. See the [migration guide](BREAKING_CHANGES_FOR_V15.md#removal-of-latest_supported_admin_version-and-release_candidate_admin_version-constants) for details.
-**Authorization Code Grant**: The OAuth flow will request expiring offline access tokens by sending `expiring: 1` parameter
329
+
-**Token Exchange**: When requesting offline access tokens via token exchange, the flow will request expiring tokens
330
+
331
+
The resulting `Session` object will contain:
332
+
-`access_token`: The access token that will eventually expire
333
+
-`expires`: The expiration time for the access token
334
+
-`refresh_token`: A token that can be used to refresh the access token
335
+
-`refresh_token_expires`: The expiration time for the refresh token
336
+
337
+
### Refreshing Access Tokens
338
+
339
+
When your access token expires, you can use the refresh token to obtain a new access token using the `ShopifyAPI::Auth::RefreshToken.refresh_access_token` method.
|`shop`|`String`| Yes | A Shopify domain name in the form `{exampleshop}.myshopify.com`. |
345
+
|`refresh_token`|`String`| Yes | The refresh token from the session. |
346
+
347
+
#### Output
348
+
This method returns a new `ShopifyAPI::Auth::Session` object with a fresh access token and a new refresh token. Your app should store this new session to replace the expired one.
349
+
350
+
#### Example
351
+
```ruby
352
+
defrefresh_session(shop, refresh_token)
353
+
begin
354
+
# Refresh the access token using the refresh token
# Refresh token has expired, need to re-authenticate with OAuth
387
+
end
388
+
```
389
+
390
+
### Migrating Non-Expiring Tokens to Expiring Tokens
391
+
392
+
If you have existing non-expiring offline access tokens and want to migrate them to expiring tokens, you can use the `ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token` method. This performs a token exchange that converts your non-expiring offline token into an expiring one with a refresh token.
393
+
394
+
> [!WARNING]
395
+
> This is a **one-time, irreversible migration** per shop. Once you migrate a shop's token to an expiring token, you cannot convert it back to a non-expiring token. The shop would need to reinstall your app with `expiring_offline_access_tokens: false` in your Context configuration to obtain a new non-expiring token.
|`shop`|`String`| Yes | A Shopify domain name in the form `{exampleshop}.myshopify.com`. |
401
+
|`non_expiring_offline_token`|`String`| Yes | The non-expiring offline access token to migrate. |
402
+
403
+
#### Output
404
+
This method returns a new `ShopifyAPI::Auth::Session` object with an expiring access token and refresh token. Your app should store this new session to replace the non-expiring one.
When migrating your app to use expiring tokens, follow this order:
425
+
426
+
1.**Update your database schema** to add `expires_at` (timestamp), `refresh_token` (string) and `refresh_token_expires` (timestamp) columns to your session storage
427
+
2.**Implement refresh logic** in your app to handle token expiration using `ShopifyAPI::Auth::RefreshToken.refresh_access_token`
428
+
3.**Enable expiring tokens in your Context setup** so new installations will request and receive expiring tokens:
429
+
```ruby
430
+
ShopifyAPI::Context.setup(
431
+
expiring_offline_access_tokens:true,
432
+
# ... other config
433
+
)
434
+
```
435
+
4.**Migrate existing non-expiring tokens** for shops that have already installed your app using the migration method above
436
+
308
437
## Using OAuth Session to make authenticated API calls
309
438
Once your OAuth flow is complete, and you have persisted your `Session` object, you may use that `Session` object to make authenticated API calls.
0 commit comments