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
+3-4Lines changed: 3 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,12 +3,11 @@ 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
6
+
- Adds support for expiring offline access tokens with automatic refresh for `ShopSessionStorage`. Apps can now opt-in to expiring offline tokens via `ShopifyAPI::Context.setup(offline_access_token_expires: true)`, and `ShopSessionStorage` will automatically refresh expired tokens when using `with_shopify_session`. **See [migration guide](/docs/shopify_app/sessions.md#migrating-to-expiring-offline-access-tokens) for setup instructions.**[#XXXX](https://github.com/Shopify/shopify_app/pull/XXXX)
9
7
-`ShopSessionStorage` now automatically stores `access_scopes`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` from auth sessions
10
8
-`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
9
+
- Adds `refresh_token_if_expired!` public method to `ShopSessionStorage` for manual token refresh
10
+
- Adds `RefreshTokenExpiredError` exception raised when refresh token itself is expired
12
11
- 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)
13
12
- 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)
14
13
- Handle invalid token when adding redirection headers [#1945](https://github.com/Shopify/shopify_app/pull/1945)
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.
82
+
3.**Optional:** You can now opt-in to using expiring offline access tokens with automatic refresh. See the [Sessions documentation](/docs/shopify_app/sessions.md#offline-access-tokens) for setup instructions.
94
83
95
84
**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.
-[Migrating to Expiring Offline Access Tokens](#migrating-to-expiring-offline-access-tokens)
26
27
-[Migrating from shop-based to user-based token strategy](#migrating-from-shop-based-to-user-based-token-strategy)
27
28
-[Migrating from `ShopifyApi::Auth::SessionStorage` to `ShopifyApp::SessionStorage`](#migrating-from-shopifyapiauthsessionstorage-to-shopifyappsessionstorage)
28
29
@@ -206,60 +207,18 @@ user.with_shopify_session do
206
207
end
207
208
```
208
209
209
-
##### Automatic Access Token Refresh
210
+
**Automatic Token Refresh for Shop Sessions:**
210
211
211
-
`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
+
When using `Shop` models with [expiring offline access tokens](#migrating-to-expiring-offline-access-tokens) configured, `with_shopify_session`will automatically refresh expired tokens before executing the block. This ensures your API calls always use valid credentials without manual intervention.
212
213
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
214
+
To disable automatic refresh, pass `auto_refresh: false`:
# 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
217
shop.with_shopify_session(auto_refresh:false) do
243
218
# 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
219
end
254
220
```
255
221
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
-
263
222
#### Re-fetching an access token when API returns Unauthorized
264
223
265
224
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.
@@ -355,41 +314,96 @@ end
355
314
```
356
315
357
316
## 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.
317
+
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 token when it is expired.
318
+
This requires the `ShopifyAPI::Auth::Session``expires` attribute to be stored.
319
+
320
+
**Online access tokens (User sessions):**
321
+
- 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
322
+
- Online access tokens cannot be refreshed, so when the token is expired, the user must go through the OAuth flow again to get a new token
323
+
324
+
**Offline access tokens (Shop sessions):**
325
+
- Offline access tokens can optionally be configured to expire and support automatic refresh. See [Migrating to Expiring Offline Access Tokens](#migrating-to-expiring-offline-access-tokens) for detailed setup instructions
326
+
327
+
## Migrating to Expiring Offline Access Tokens
328
+
329
+
You can opt-in to expiring offline access tokens for enhanced security. When enabled, Shopify will issue offline access tokens with an expiration date and a refresh token. `ShopSessionStorage` will then automatically refresh expired tokens when using `with_shopify_session`.
330
+
331
+
**1. Database Setup:**
332
+
333
+
Run the shop model generator (use `--skip` to avoid regenerating the Shop model if it already exists):
360
334
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.
335
+
```bash
336
+
rails generate shopify_app:shop_model --skip
337
+
```
363
338
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.
339
+
The generator will prompt you to create a migration that adds the `expires_at`, `refresh_token`, and `refresh_token_expires_at` columns. Alternatively, you can create the migration manually:
**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`:
351
+
**2. Configuration:**
369
352
370
353
```ruby
371
354
# config/initializers/shopify_app.rb
372
355
ShopifyApp.configure do |config|
373
356
# ... other configuration
374
357
375
-
# Enable checking session expiry dates
358
+
# Enable automatic reauthentication when session is expired
376
359
config.check_session_expiry_date =true
377
360
end
378
361
379
-
# For ShopifyAPI Context - enable expiring offline tokens
362
+
# For ShopifyAPI Context - enable requesting expiring offline tokens
380
363
ShopifyAPI::Context.setup(
381
364
# ... other configuration
382
-
offline_access_token_expires:true, # Opt-in to expiring offline tokens
365
+
offline_access_token_expires:true, # Opt-in to start requesting expiring offline tokens
383
366
)
384
367
```
385
368
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.
369
+
**3. Refreshing Expired Tokens:**
370
+
371
+
With the configuration enabled, expired tokens are automatically handled differently based on the flow:
387
372
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.
When `check_session_expiry_date` is enabled, expired sessions trigger automatic re-authentication through the OAuth flow. This happens transparently when using controller concerns like `EnsureHasSession`.
375
+
376
+
**For background jobs and non-user interactions:**
377
+
Tokens are automatically refreshed when using `with_shopify_session`:
# If the token is expired, it will be automatically refreshed before making API calls
385
+
end
389
386
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.
387
+
# Disable automatic refresh if needed
388
+
shop.with_shopify_session(auto_refresh:false) do
389
+
# Token will NOT be refreshed even if expired
390
+
end
391
+
392
+
# Manual refresh
393
+
begin
394
+
shop.refresh_token_if_expired!
395
+
rescueShopifyApp::RefreshTokenExpiredError
396
+
# Handle case where refresh token itself has expired
397
+
# App needs to go through OAuth flow again
398
+
end
399
+
```
400
+
401
+
**Error Handling:**
402
+
-`ShopifyApp::RefreshTokenExpiredError` is raised when the refresh token itself is expired
403
+
- When this happens, the shop must go through the OAuth flow again to get new tokens
404
+
- The refresh process uses database row-level locking to prevent race conditions from concurrent requests
391
405
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.
406
+
**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. 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.
393
407
394
408
## Migrating from shop-based to user-based token strategy
0 commit comments