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: CHANGELOG.md
+7Lines changed: 7 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,6 +3,13 @@ Unreleased
3
3
- ⚠️ [Breaking] Removes `ShopifyApp::JWTMiddleware` and `ShopifyApp::JWT` See [Upgrading](/docs/Upgrading.md) for more migration. [1960](https://github.com/Shopify/shopify_app/pull/1960)
4
4
- ⚠️ [Breaking] Removed deprecated `CallbackController` methods. `perform_after_authenticate_job`, `install_webhooks`, and `perform_post_authenticate_jobs` have been removed. [#1961](https://github.com/Shopify/shopify_app/pull/1961)
5
5
- ⚠️ [Breaking] Bumps minimum supported Ruby version to 3.1 [#1959](https://github.com/Shopify/shopify_app/pull/1959)
6
+
- Adds automatic offline access token refresh support for `ShopSessionStorage`. When using `with_shopify_session`, expired offline access tokens will automatically be refreshed using refresh tokens. [#XXXX](https://github.com/Shopify/shopify_app/pull/XXXX)
7
+
- Adds `refresh_token_if_expired!` public method to `ShopSessionStorage` for manual token refresh
8
+
- Adds `RefreshTokenExpiredError` exception raised when refresh token itself is expired
9
+
-`ShopSessionStorage` now automatically stores `access_scopes`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` from auth sessions
10
+
-`UserSessionStorage` now automatically stores `access_scopes` and `expires_at` from auth sessions (refresh tokens not applicable for online/user tokens)
11
+
- See [Sessions documentation](/docs/shopify_app/sessions.md#automatic-access-token-refresh) for migration guide
12
+
- Deprecates `ShopSessionStorageWithScopes` and `UserSessionStorageWithScopes` in favor of `ShopSessionStorage` and `UserSessionStorage`, which now handle session attributes automatically. Will be removed in v23.0.0. [#XXXX](https://github.com/Shopify/shopify_app/pull/XXXX)
6
13
- Adds a `script_tag_manager` that will automatically create script tags when the app is installed. [1948](https://github.com/Shopify/shopify_app/pull/1948)
7
14
- Handle invalid token when adding redirection headers [#1945](https://github.com/Shopify/shopify_app/pull/1945)
8
15
- Handle invalid record error for concurrent token exchange calls [#1966](https://github.com/Shopify/shopify_app/pull/1966)
Copy file name to clipboardExpand all lines: docs/Upgrading.md
+47Lines changed: 47 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -47,6 +47,53 @@ If you do run into issues, we recommend looking at our [debugging tips.](https:/
47
47
#### (v23.0.0) Drops support for Ruby 3.0
48
48
The minimum ruby version is now 3.1
49
49
50
+
#### (v23.0.0) - ShopSessionStorageWithScopes and UserSessionStorageWithScopes are deprecated
51
+
52
+
`ShopSessionStorageWithScopes` and `UserSessionStorageWithScopes` are now deprecated in favor of `ShopSessionStorage` and `UserSessionStorage`, which handle all session attributes automatically (including `access_scopes`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` for shops).
53
+
54
+
**Migration:**
55
+
56
+
1. Update your Shop model to use `ShopSessionStorage`:
57
+
```ruby
58
+
# Before
59
+
classShop < ActiveRecord::Base
60
+
includeShopifyApp::ShopSessionStorageWithScopes
61
+
end
62
+
63
+
# After
64
+
classShop < ActiveRecord::Base
65
+
includeShopifyApp::ShopSessionStorage
66
+
end
67
+
```
68
+
69
+
2. Update your User model to use `UserSessionStorage`:
70
+
```ruby
71
+
# Before
72
+
classUser < ActiveRecord::Base
73
+
includeShopifyApp::UserSessionStorageWithScopes
74
+
end
75
+
76
+
# After
77
+
classUser < ActiveRecord::Base
78
+
includeShopifyApp::UserSessionStorage
79
+
end
80
+
```
81
+
82
+
3.**Optional but recommended:** Add columns to enable automatic token refresh for shops:
With these columns, `ShopSessionStorage#with_shopify_session` will automatically refresh expired offline access tokens. See the [Sessions documentation](/docs/shopify_app/sessions.md#automatic-access-token-refresh) for more details.
94
+
95
+
**Note:** If you had custom `access_scopes=` or `access_scopes` methods in your models, these are no longer needed. The base concerns now handle these attributes automatically.
96
+
50
97
#### (v23.0.0) - Deprecated methods in CallbackController
51
98
The following methods from `ShopifyApp::CallbackController` have been deprecated in `v23.0.0`
-[ShopSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/shop_session_storage_with_scopes.rb) (Deprecated in 23.0.0)
-[UserSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/user_session_storage_with_scopes.rb) (Deprecated in 23.0.0)
`ShopSessionStorage` includes automatic token refresh for expired offline access tokens. When using `with_shopify_session` on a Shop model, the gem will automatically refresh the access token if it has expired, using the refresh token stored in the database.
212
+
213
+
**Requirements:**
214
+
- Shop model must include `ShopSessionStorage` concern
215
+
- Database must have the following columns:
216
+
-`expires_at` (datetime) - when the access token expires
217
+
-`refresh_token` (string) - the refresh token
218
+
-`refresh_token_expires_at` (datetime) - when the refresh token expires
# If the token is expired, it will be automatically refreshed before making API calls
238
+
ShopifyAPI::Product.all
239
+
end
240
+
241
+
# Disable automatic refresh if needed
242
+
shop.with_shopify_session(auto_refresh:false) do
243
+
# Token will NOT be refreshed even if expired
244
+
ShopifyAPI::Product.all
245
+
end
246
+
247
+
# Manual refresh
248
+
begin
249
+
shop.refresh_token_if_expired!
250
+
rescueShopifyApp::RefreshTokenExpiredError
251
+
# Handle case where refresh token itself has expired
252
+
# App needs to go through OAuth flow again
253
+
end
254
+
```
255
+
256
+
**Error Handling:**
257
+
-`ShopifyApp::RefreshTokenExpiredError` is raised when the refresh token itself is expired
258
+
- When this happens, the shop must go through the OAuth flow again to get new tokens
259
+
- The refresh process uses database row-level locking to prevent race conditions from concurrent requests
260
+
261
+
**Note:** Refresh tokens are only available for offline (shop) access tokens. Online (user) access tokens do not support refresh and must be re-authorized through OAuth when expired.
262
+
209
263
#### Re-fetching an access token when API returns Unauthorized
210
264
211
265
When using `ShopifyApp::EnsureHasSession` and the `new_embedded_auth_strategy` configuration, any **unhandled** Unauthorized `ShopifyAPI::Errors::HttpResponseError` will cause the app to perform token exchange to fetch a new access token from Shopify and the action to be executed again. This will update and store the new access token to the current session instance.
@@ -300,39 +354,42 @@ class MyController < ApplicationController
300
354
end
301
355
```
302
356
303
-
## Access scopes
304
-
If you want to customize how access scopes are stored for shops and users, you can implement the `access_scopes` getters and setters in the models that include `ShopifyApp::ShopSessionStorageWithScopes` and `ShopifyApp::UserSessionStorageWithScopes` as shown:
357
+
## Expiry date
358
+
When the configuration flag `check_session_expiry_date` is set to true, the session expiry date will be checked to trigger a re-auth and get a fresh user token when it is expired.
359
+
This requires the `ShopifyAPI::Auth::Session``expires` attribute to be stored.
305
360
306
-
### `ShopifyApp::ShopSessionStorageWithScopes`
307
-
```ruby
308
-
classShop < ActiveRecord::Base
309
-
includeShopifyApp::ShopSessionStorageWithScopes
361
+
### Online access tokens
362
+
When the `User` model includes the `UserSessionStorage` concern, a DB migration can be generated with `rails generate shopify_app:user_model --skip` to add the `expires_at` attribute to the model.
310
363
311
-
defaccess_scopes=(scopes)
312
-
# Store access scopes
313
-
end
314
-
defaccess_scopes
315
-
# Find access scopes
316
-
end
317
-
end
318
-
```
364
+
Online access tokens can not be refreshed, so when the token is expired, the user must go through the OAuth flow again to get a new token.
365
+
366
+
### Offline access tokens
367
+
368
+
**Optional Configuration:** By default, offline access tokens do not expire. However, you can opt-in to expiring offline access tokens for enhanced security by configuring it through `ShopifyAPI::Context`:
319
369
320
-
### `ShopifyApp::UserSessionStorageWithScopes`
321
370
```ruby
322
-
classUser < ActiveRecord::Base
323
-
includeShopifyApp::UserSessionStorageWithScopes
371
+
# config/initializers/shopify_app.rb
372
+
ShopifyApp.configure do |config|
373
+
# ... other configuration
324
374
325
-
defaccess_scopes=(scopes)
326
-
# Store access scopes
327
-
end
328
-
defaccess_scopes
329
-
# Find access scopes
330
-
end
375
+
# Enable checking session expiry dates
376
+
config.check_session_expiry_date =true
331
377
end
378
+
379
+
# For ShopifyAPI Context - enable expiring offline tokens
380
+
ShopifyAPI::Context.setup(
381
+
# ... other configuration
382
+
offline_access_token_expires:true, # Opt-in to expiring offline tokens
383
+
)
332
384
```
333
385
334
-
## Expiry date
335
-
When the configuration flag `check_session_expiry_date` is set to true, the user session expiry date will be checked to trigger a re-auth and get a fresh user token when it is expired. This requires the `ShopifyAPI::Auth::Session``expires` attribute to be stored. When the `User` model includes the `UserSessionStorageWithScopes` concern, a DB migration can be generated with `rails generate shopify_app:user_model --skip` to add the `expires_at` attribute to the model.
386
+
When expiring offline tokens are enabled, Shopify will issue offline access tokens with an expiration date and a refresh token. Your app can then automatically refresh these tokens when they expire.
387
+
388
+
**Database Setup:** When the `Shop` model includes the `ShopSessionStorage` concern, a DB migration can be generated with `rails generate shopify_app:shop_model --skip` to add the `expires_at`, `refresh_token`, and `refresh_token_expires_at` attributes to the model.
389
+
390
+
**Automatic Refresh:** Offline access tokens can be automatically refreshed using the stored refresh token when expired. See [Automatic Access Token Refresh](#automatic-access-token-refresh) for more details.
391
+
392
+
**Note:** If you choose not to enable expiring offline tokens, the `expires_at`, `refresh_token`, and `refresh_token_expires_at` columns will remain `NULL` and no automatic refresh will occur.
336
393
337
394
## Migrating from shop-based to user-based token strategy
0 commit comments