shopify_app 22.5.2 → 23.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yaml +6 -0
  3. data/.github/workflows/build.yml +5 -5
  4. data/.github/workflows/close-waiting-for-response-issues.yml +1 -1
  5. data/.github/workflows/release.yml +2 -2
  6. data/.github/workflows/remove-labels-on-activity.yml +2 -3
  7. data/.github/workflows/rubocop.yml +2 -2
  8. data/CHANGELOG.md +22 -0
  9. data/Gemfile +1 -1
  10. data/Gemfile.lock +181 -122
  11. data/README.md +105 -25
  12. data/Rakefile +13 -0
  13. data/app/controllers/shopify_app/callback_controller.rb +2 -40
  14. data/app/controllers/shopify_app/extension_verification_controller.rb +1 -1
  15. data/app/jobs/shopify_app/script_tags_manager_job.rb +16 -0
  16. data/docs/Releasing.md +113 -19
  17. data/docs/Upgrading.md +72 -0
  18. data/docs/shopify_app/content-security-policy.md +50 -3
  19. data/docs/shopify_app/controller-concerns.md +20 -0
  20. data/docs/shopify_app/script-tags.md +52 -0
  21. data/docs/shopify_app/sessions.md +149 -22
  22. data/lib/generators/shopify_app/add_app_uninstalled_job/templates/app_uninstalled_job.rb.tt +2 -2
  23. data/lib/generators/shopify_app/add_privacy_jobs/templates/customers_data_request_job.rb.tt +2 -2
  24. data/lib/generators/shopify_app/add_privacy_jobs/templates/customers_redact_job.rb.tt +2 -2
  25. data/lib/generators/shopify_app/add_privacy_jobs/templates/shop_redact_job.rb.tt +2 -2
  26. data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb.tt +2 -2
  27. data/lib/generators/shopify_app/install/install_generator.rb +1 -1
  28. data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +18 -0
  29. data/lib/generators/shopify_app/shop_model/templates/db/migrate/add_shop_access_token_expiry_columns.erb +7 -0
  30. data/lib/generators/shopify_app/shop_model/templates/shop.rb +1 -1
  31. data/lib/generators/shopify_app/user_model/templates/user.rb +1 -1
  32. data/lib/shopify_app/auth/post_authenticate_tasks.rb +8 -0
  33. data/lib/shopify_app/auth/token_exchange.rb +7 -0
  34. data/lib/shopify_app/configuration.rb +5 -5
  35. data/lib/shopify_app/controller_concerns/login_protection.rb +12 -8
  36. data/lib/shopify_app/engine.rb +2 -5
  37. data/lib/shopify_app/errors.rb +2 -0
  38. data/lib/shopify_app/managers/script_tags_manager.rb +348 -0
  39. data/lib/shopify_app/session/shop_session_storage.rb +84 -2
  40. data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +6 -0
  41. data/lib/shopify_app/session/user_session_storage.rb +21 -2
  42. data/lib/shopify_app/session/user_session_storage_with_scopes.rb +6 -0
  43. data/lib/shopify_app/utils.rb +1 -1
  44. data/lib/shopify_app/version.rb +1 -1
  45. data/lib/shopify_app.rb +12 -7
  46. data/package.json +1 -1
  47. data/shopify_app.gemspec +9 -10
  48. data/translation.yml +1 -0
  49. data/yarn.lock +7 -9
  50. metadata +63 -46
  51. data/lib/shopify_app/middleware/jwt_middleware.rb +0 -48
  52. data/lib/shopify_app/session/jwt.rb +0 -73
  53. /data/{lib/shopify_app/jobs → app/jobs/shopify_app}/webhooks_manager_job.rb +0 -0
@@ -23,6 +23,7 @@ Sessions are used to make contextual API calls for either a shop (offline sessio
23
23
  - [Access scopes](#access-scopes)
24
24
  - [`ShopifyApp::ShopSessionStorageWithScopes`](#shopifyappshopsessionstoragewithscopes)
25
25
  - [`ShopifyApp::UserSessionStorageWithScopes`](#shopifyappusersessionstoragewithscopes)
26
+ - [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
 
@@ -129,11 +130,11 @@ These methods are already implemented as a part of the `User` and `Shop` models
129
130
  Simply include these concerns if you want to use the implementation, and overwrite methods for custom implementation
130
131
 
131
132
  - `Shop` storage
132
- - [ShopSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/shop_session_storage_with_scopes.rb)
133
+ - [ShopSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/shop_session_storage_with_scopes.rb) (Deprecated in 23.0.0)
133
134
  - [ShopSessionStorage](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/shop_session_storage.rb)
134
135
 
135
136
  - `User` storage
136
- - [UserSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/user_session_storage_with_scopes.rb)
137
+ - [UserSessionStorageWithScopes](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/user_session_storage_with_scopes.rb) (Deprecated in 23.0.0)
137
138
  - [UserSessionStorage](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/session/user_session_storage.rb)
138
139
 
139
140
  ### Loading Sessions
@@ -206,6 +207,18 @@ user.with_shopify_session do
206
207
  end
207
208
  ```
208
209
 
210
+ **Automatic Token Refresh for Shop Sessions:**
211
+
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.
213
+
214
+ To disable automatic refresh, pass `auto_refresh: false`:
215
+
216
+ ```ruby
217
+ shop.with_shopify_session(auto_refresh: false) do
218
+ # Token will NOT be refreshed even if expired
219
+ end
220
+ ```
221
+
209
222
  #### Re-fetching an access token when API returns Unauthorized
210
223
 
211
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.
@@ -300,39 +313,153 @@ class MyController < ApplicationController
300
313
  end
301
314
  ```
302
315
 
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:
316
+ ## Expiry date
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 Migration:**
332
+
333
+ Run the shop model generator (use `--skip` to avoid regenerating the Shop model if it already exists):
334
+
335
+ ```bash
336
+ rails generate shopify_app:shop_model --skip
337
+ ```
338
+
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:
340
+
341
+ ```ruby
342
+ class AddShopAccessTokenExpiryColumns < ActiveRecord::Migration[7.0]
343
+ def change
344
+ add_column :shops, :expires_at, :datetime
345
+ add_column :shops, :refresh_token, :string
346
+ add_column :shops, :refresh_token_expires_at, :datetime
347
+ end
348
+ end
349
+ ```
350
+
351
+ **2. Update Model Concern:**
352
+
353
+ If your Shop model is using the deprecated `ShopSessionStorageWithScopes` concern, update it to use `ShopSessionStorage`:
305
354
 
306
- ### `ShopifyApp::ShopSessionStorageWithScopes`
307
355
  ```ruby
356
+ # app/models/shop.rb
308
357
  class Shop < ActiveRecord::Base
309
- include ShopifyApp::ShopSessionStorageWithScopes
358
+ include ShopifyApp::ShopSessionStorage # Change from ShopSessionStorageWithScopes
359
+ end
360
+ ```
310
361
 
311
- def access_scopes=(scopes)
312
- # Store access scopes
313
- end
314
- def access_scopes
315
- # Find access scopes
316
- end
362
+ `ShopSessionStorage` now automatically handles `access_scopes`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` - no additional concerns needed.
363
+
364
+ **3. Configuration:**
365
+
366
+ ```ruby
367
+ # config/initializers/shopify_app.rb
368
+ ShopifyApp.configure do |config|
369
+ # ... other configuration
370
+
371
+ # Enable automatic reauthentication when session is expired
372
+ config.check_session_expiry_date = true
317
373
  end
374
+
375
+ # For ShopifyAPI Context - enable requesting expiring offline tokens
376
+ ShopifyAPI::Context.setup(
377
+ # ... other configuration
378
+ expiring_offline_access_tokens: true, # Opt-in to start requesting expiring offline tokens
379
+ )
318
380
  ```
319
381
 
320
- ### `ShopifyApp::UserSessionStorageWithScopes`
382
+ **4. Refreshing Expired Tokens:**
383
+
384
+ With the configuration enabled, expired tokens are automatically handled differently based on the flow:
385
+
386
+ **For user-facing requests (OAuth/Token Exchange flow):**
387
+ 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`.
388
+
389
+ **For background jobs and non-user interactions:**
390
+ Tokens are automatically refreshed when using `with_shopify_session` from `ShopSessionStorage`:
391
+
321
392
  ```ruby
322
- class User < ActiveRecord::Base
323
- include ShopifyApp::UserSessionStorageWithScopes
393
+ shop = Shop.find_by(shopify_domain: "example.myshopify.com")
324
394
 
325
- def access_scopes=(scopes)
326
- # Store access scopes
327
- end
328
- def access_scopes
329
- # Find access scopes
395
+ # Automatic refresh (default behavior)
396
+ shop.with_shopify_session do
397
+ # If the token is expired, it will be automatically refreshed before making API calls
398
+ end
399
+
400
+ # Disable automatic refresh if needed
401
+ shop.with_shopify_session(auto_refresh: false) do
402
+ # Token will NOT be refreshed even if expired
403
+ end
404
+
405
+ # Manual refresh
406
+ begin
407
+ shop.refresh_token_if_expired!
408
+ rescue ShopifyApp::RefreshTokenExpiredError
409
+ # Handle case where refresh token itself has expired
410
+ # App needs to go through OAuth flow again
411
+ end
412
+ ```
413
+
414
+ **Error Handling:**
415
+ - `ShopifyApp::RefreshTokenExpiredError` is raised when the refresh token itself is expired
416
+ - When this happens, the user must interact with the app to go through the OAuth flow again to get new tokens
417
+ - The refresh process uses database row-level locking to prevent race conditions from concurrent requests
418
+
419
+ **5. Migrating Existing Shop Installations:**
420
+
421
+ ⚠️ **Important:** When you enable `offline_access_token_expires: true`, only **new shop installations** will automatically receive expiring tokens during the OAuth flow. Existing shop installations with non-expiring tokens will continue using their current tokens until manually migrated.
422
+
423
+ To migrate existing shops to expiring tokens, use the `ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token` method. Here's an example background job to migrate all existing shops:
424
+
425
+ ```ruby
426
+ # app/jobs/migrate_shops_to_expiring_tokens_job.rb
427
+ class MigrateShopsToExpiringTokensJob < ActiveJob::Base
428
+ queue_as :default
429
+
430
+ def perform
431
+ # Find shops that haven't been migrated yet (no refresh_token or expires_at)
432
+ shops_to_migrate = Shop.where(expires_at: nil, refresh_token: nil, refresh_token_expires_at: nil)
433
+
434
+ shops_to_migrate.find_each do |shop|
435
+ begin
436
+ # Migrate to expiring token
437
+ new_session = ShopifyAPI::Auth::TokenExchange.migrate_to_expiring_token(
438
+ shop: shop.shopify_domain,
439
+ non_expiring_offline_token: shop.shopify_token
440
+ )
441
+
442
+ # Store the new session with expiring token and refresh token
443
+ Shop.store(new_session)
444
+
445
+ Rails.logger.info("Successfully migrated #{shop.shopify_domain} to expiring token")
446
+ rescue ShopifyAPI::Errors::HttpResponseError => e
447
+ # Handle migration errors (e.g., shop uninstalled, network issues)
448
+ Rails.logger.error("Failed to migrate #{shop.shopify_domain}: #{e.message}")
449
+ rescue => e
450
+ Rails.logger.error("Unexpected error migrating #{shop.shopify_domain}: #{e.message}")
451
+ end
452
+ end
330
453
  end
331
454
  end
332
455
  ```
333
456
 
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.
457
+ **Migration notes:**
458
+ - This is a **one-time, irreversible operation** per shop
459
+ - The shop must have the app installed and have a valid access token
460
+ - After migration, the shop's offline token will have an expiration date and a refresh token
461
+
462
+ **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.
336
463
 
337
464
  ## Migrating from shop-based to user-based token strategy
338
465
 
@@ -1,8 +1,8 @@
1
1
  class AppUninstalledJob < ActiveJob::Base
2
- extend ShopifyAPI::Webhooks::Handler
2
+ include ShopifyAPI::Webhooks::WebhookHandler
3
3
 
4
4
  class << self
5
- def handle(topic:, shop:, body:)
5
+ def handle(topic:, shop:, body:, webhook_id:, api_version:)
6
6
  perform_later(topic: topic, shop_domain: shop, webhook: body)
7
7
  end
8
8
  end
@@ -1,8 +1,8 @@
1
1
  class CustomersDataRequestJob < ActiveJob::Base
2
- extend ShopifyAPI::Webhooks::Handler
2
+ include ShopifyAPI::Webhooks::WebhookHandler
3
3
 
4
4
  class << self
5
- def handle(topic:, shop:, body:)
5
+ def handle(topic:, shop:, body:, webhook_id:, api_version:)
6
6
  perform_later(topic: topic, shop_domain: shop, webhook: body)
7
7
  end
8
8
  end
@@ -1,8 +1,8 @@
1
1
  class CustomersRedactJob < ActiveJob::Base
2
- extend ShopifyAPI::Webhooks::Handler
2
+ include ShopifyAPI::Webhooks::WebhookHandler
3
3
 
4
4
  class << self
5
- def handle(topic:, shop:, body:)
5
+ def handle(topic:, shop:, body:, webhook_id:, api_version:)
6
6
  perform_later(topic: topic, shop_domain: shop, webhook: body)
7
7
  end
8
8
  end
@@ -1,8 +1,8 @@
1
1
  class ShopRedactJob < ActiveJob::Base
2
- extend ShopifyAPI::Webhooks::Handler
2
+ include ShopifyAPI::Webhooks::WebhookHandler
3
3
 
4
4
  class << self
5
- def handle(topic:, shop:, body:)
5
+ def handle(topic:, shop:, body:, webhook_id:, api_version:)
6
6
  perform_later(topic: topic, shop_domain: shop, webhook: body)
7
7
  end
8
8
  end
@@ -1,8 +1,8 @@
1
1
  class <%= @job_class_name %> < ActiveJob::Base
2
- extend ShopifyAPI::Webhooks::Handler
2
+ include ShopifyAPI::Webhooks::WebhookHandler
3
3
 
4
4
  class << self
5
- def handle(topic:, shop:, body:)
5
+ def handle(topic:, shop:, body:, webhook_id:, api_version:)
6
6
  perform_later(topic: topic, shop_domain: shop, webhook: body)
7
7
  end
8
8
  end
@@ -19,7 +19,7 @@ module ShopifyApp
19
19
  def create_shopify_app_initializer
20
20
  @application_name = format_array_argument(options["application_name"])
21
21
  @scope = format_array_argument(options["scope"])
22
- @api_version = options["api_version"] || ShopifyAPI::LATEST_SUPPORTED_ADMIN_VERSION
22
+ @api_version = options["api_version"] || "2025-10"
23
23
 
24
24
  template("shopify_app.rb", "config/initializers/shopify_app.rb")
25
25
  end
@@ -40,6 +40,24 @@ module ShopifyApp
40
40
  end
41
41
  end
42
42
 
43
+ def create_shop_with_token_refresh_migration
44
+ token_refresh_prompt = <<~PROMPT
45
+ To support expiring offline access token with refresh, your Shop model needs to store \
46
+ token expiration dates and refresh tokens.
47
+
48
+ The following migration will add `expires_at`, `refresh_token`, and \
49
+ `refresh_token_expires_at` columns to the Shop model. \
50
+ Do you want to include this migration? [y/n]
51
+ PROMPT
52
+
53
+ if new_shopify_cli_app? || Rails.env.test? || yes?(token_refresh_prompt)
54
+ migration_template(
55
+ "db/migrate/add_shop_access_token_expiry_columns.erb",
56
+ "db/migrate/add_shop_access_token_expiry_columns.rb",
57
+ )
58
+ end
59
+ end
60
+
43
61
  def update_shopify_app_initializer
44
62
  gsub_file("config/initializers/shopify_app.rb", "ShopifyApp::InMemoryShopSessionStore", "Shop")
45
63
  end
@@ -0,0 +1,7 @@
1
+ class AddShopAccessTokenExpiryColumns < ActiveRecord::Migration[<%= rails_migration_version %>]
2
+ def change
3
+ add_column :shops, :expires_at, :datetime
4
+ add_column :shops, :refresh_token, :string
5
+ add_column :shops, :refresh_token_expires_at, :datetime
6
+ end
7
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Shop < ActiveRecord::Base
4
- include ShopifyApp::ShopSessionStorageWithScopes
4
+ include ShopifyApp::ShopSessionStorage
5
5
 
6
6
  def api_version
7
7
  ShopifyApp.configuration.api_version
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class User < ActiveRecord::Base
4
- include ShopifyApp::UserSessionStorageWithScopes
4
+ include ShopifyApp::UserSessionStorage
5
5
 
6
6
  def api_version
7
7
  ShopifyApp.configuration.api_version
@@ -10,6 +10,7 @@ module ShopifyApp
10
10
  session_for_shop = session.online? ? shop_session(session) : session
11
11
 
12
12
  install_webhooks(session_for_shop)
13
+ install_scripttags(session_for_shop)
13
14
 
14
15
  perform_after_authenticate_job(session)
15
16
  end
@@ -27,6 +28,13 @@ module ShopifyApp
27
28
  WebhooksManager.queue(session.shop, session.access_token)
28
29
  end
29
30
 
31
+ def install_scripttags(session)
32
+ ShopifyApp::Logger.debug("PostAuthenticateTasks: Installing scripttags")
33
+ return unless ShopifyApp.configuration.has_script_tags?
34
+
35
+ ScriptTagsManager.queue(session.shop, session.access_token, ShopifyApp.configuration.script_tags)
36
+ end
37
+
30
38
  def perform_after_authenticate_job(session)
31
39
  ShopifyApp::Logger.debug("PostAuthenticateTasks: Performing after_authenticate_job")
32
40
  config = ShopifyApp.configuration.after_authenticate_job
@@ -60,6 +60,13 @@ module ShopifyApp
60
60
  rescue ActiveRecord::RecordNotUnique
61
61
  Logger.debug("Session not stored due to concurrent token exchange calls")
62
62
  session
63
+ rescue ActiveRecord::RecordInvalid => e
64
+ if e.message.include?("has already been taken")
65
+ Logger.debug("Session not stored due to concurrent token exchange calls")
66
+ session
67
+ else
68
+ raise
69
+ end
63
70
  rescue => error
64
71
  Logger.error("An error occurred during the token exchange: [#{error.class}] #{error.message}")
65
72
  raise
@@ -15,7 +15,7 @@ module ShopifyApp
15
15
  attr_accessor :embedded_app
16
16
  alias_method :embedded_app?, :embedded_app
17
17
  attr_accessor :webhooks
18
- attr_accessor :scripttags
18
+ attr_accessor :script_tags
19
19
  attr_accessor :after_authenticate_job
20
20
  attr_accessor :api_version
21
21
 
@@ -33,7 +33,7 @@ module ShopifyApp
33
33
  attr_accessor :custom_post_authenticate_tasks
34
34
 
35
35
  # customise ActiveJob queue names
36
- attr_accessor :scripttags_manager_queue_name
36
+ attr_accessor :script_tags_manager_queue_name
37
37
  attr_accessor :webhooks_manager_queue_name
38
38
 
39
39
  # configure myshopify domain for local shopify development
@@ -58,7 +58,7 @@ module ShopifyApp
58
58
  @root_url = "/"
59
59
  @myshopify_domain = "myshopify.com"
60
60
  @unified_admin_domain = "shopify.com"
61
- @scripttags_manager_queue_name = Rails.application.config.active_job.queue_name
61
+ @script_tags_manager_queue_name = Rails.application.config.active_job.queue_name
62
62
  @webhooks_manager_queue_name = Rails.application.config.active_job.queue_name
63
63
  @disable_webpacker = ENV["SHOPIFY_APP_DISABLE_WEBPACKER"].present?
64
64
  @scope = []
@@ -115,8 +115,8 @@ module ShopifyApp
115
115
  webhooks.present?
116
116
  end
117
117
 
118
- def has_scripttags?
119
- scripttags.present?
118
+ def has_script_tags?
119
+ script_tags.present?
120
120
  end
121
121
 
122
122
  def requires_billing?
@@ -85,13 +85,7 @@ module ShopifyApp
85
85
  # Make sure the shop is set in the redirection URL
86
86
  unless params[:shop]
87
87
  ShopifyApp::Logger.debug("Setting current shop session")
88
- params[:shop] = if current_shopify_session
89
- current_shopify_session.shop
90
-
91
- elsif shopify_id_token
92
- jwt_payload = ShopifyAPI::Auth::JwtPayload.new(shopify_id_token)
93
- jwt_payload.shop
94
- end
88
+ params[:shop] = current_shopify_session&.shop || parse_shop_from_jwt
95
89
  end
96
90
 
97
91
  url ||= login_url_with_optional_shop
@@ -269,7 +263,7 @@ module ShopifyApp
269
263
  return ShopifyAPI::Context.load_private_session if ShopifyAPI::Context.private?
270
264
 
271
265
  session_id = ShopifyAPI::Utils::SessionUtils.current_session_id(shopify_id_token, cookies, is_online)
272
- return nil unless session_id
266
+ return unless session_id
273
267
 
274
268
  ShopifyApp::SessionRepository.load_session(session_id)
275
269
  end
@@ -279,5 +273,15 @@ module ShopifyApp
279
273
  request.media_type == "text/javascript" ||
280
274
  request.media_type == "application/javascript"
281
275
  end
276
+
277
+ def parse_shop_from_jwt
278
+ return nil unless shopify_id_token
279
+
280
+ jwt_payload = ShopifyAPI::Auth::JwtPayload.new(shopify_id_token)
281
+ jwt_payload.shop
282
+ rescue ShopifyAPI::Errors::InvalidJwtTokenError
283
+ ShopifyApp::Logger.warn("Invalid JWT token for current Shopify session")
284
+ nil
285
+ end
282
286
  end
283
287
  end
@@ -5,7 +5,7 @@ module ShopifyApp
5
5
  private
6
6
 
7
7
  def args_info(job)
8
- log_disabled_classes = ["ShopifyApp::WebhooksManagerJob"]
8
+ log_disabled_classes = ["ShopifyApp::WebhooksManagerJob", "ShopifyApp::ScriptTagsManagerJob"]
9
9
  return "" if log_disabled_classes.include?(job.class.name)
10
10
 
11
11
  super
@@ -16,10 +16,6 @@ module ShopifyApp
16
16
  engine_name "shopify_app"
17
17
  isolate_namespace ShopifyApp
18
18
 
19
- initializer "shopify_app.middleware" do |app|
20
- app.config.middleware.insert_after(::Rack::Runtime, ShopifyApp::JWTMiddleware)
21
- end
22
-
23
19
  initializer "shopify_app.assets.precompile" do |app|
24
20
  app.config.assets.precompile += [
25
21
  "shopify_app/redirect.js",
@@ -30,6 +26,7 @@ module ShopifyApp
30
26
  ActiveSupport.on_load(:active_job) do
31
27
  if ActiveJob::Base.respond_to?(:log_arguments?)
32
28
  WebhooksManagerJob.log_arguments = false
29
+ ScriptTagsManagerJob.log_arguments = false
33
30
  elsif ActiveJob::Logging::LogSubscriber.private_method_defined?(:args_info)
34
31
  ActiveJob::Logging::LogSubscriber.prepend(RedactJobParams)
35
32
  end
@@ -31,4 +31,6 @@ module ShopifyApp
31
31
  class ShopifyDomainNotFound < StandardError; end
32
32
 
33
33
  class ShopifyHostNotFound < StandardError; end
34
+
35
+ class RefreshTokenExpiredError < StandardError; end
34
36
  end