shopify_app 13.2.0 → 20.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/bug-report.md +63 -0
- data/.github/ISSUE_TEMPLATE/config.yml +1 -0
- data/.github/ISSUE_TEMPLATE/feature-request.md +33 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.github/workflows/build.yml +40 -0
- data/.github/workflows/cla.yml +22 -0
- data/.github/workflows/close-waiting-for-response-issues.yml +20 -0
- data/.github/workflows/release.yml +24 -0
- data/.github/workflows/remove-labels-on-activity.yml +16 -0
- data/.github/workflows/rubocop.yml +22 -0
- data/.github/workflows/stale.yml +31 -0
- data/.gitignore +1 -2
- data/.nvmrc +1 -1
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +221 -0
- data/CONTRIBUTING.md +81 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +248 -0
- data/README.md +74 -563
- data/Rakefile +4 -3
- data/SECURITY.md +59 -0
- data/app/assets/images/storage_access.svg +1 -2
- data/app/assets/javascripts/shopify_app/app_bridge_3.1.1.js +10 -0
- data/app/assets/javascripts/shopify_app/app_bridge_redirect.js +22 -0
- data/app/assets/javascripts/shopify_app/app_bridge_utils_3.1.1.js +1 -0
- data/app/assets/javascripts/shopify_app/post_redirect.js +9 -0
- data/app/assets/javascripts/shopify_app/redirect.js +10 -14
- data/app/assets/javascripts/shopify_app/storage_access.js +5 -10
- data/app/assets/javascripts/shopify_app/top_level_interaction.js +1 -1
- data/app/controllers/concerns/shopify_app/authenticated.rb +4 -0
- data/app/controllers/concerns/shopify_app/ensure_authenticated_links.rb +39 -0
- data/app/controllers/concerns/shopify_app/require_known_shop.rb +48 -0
- data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +40 -0
- data/app/controllers/shopify_app/authenticated_controller.rb +1 -0
- data/app/controllers/shopify_app/callback_controller.rb +56 -77
- data/app/controllers/shopify_app/extension_verification_controller.rb +2 -7
- data/app/controllers/shopify_app/sessions_controller.rb +33 -117
- data/app/controllers/shopify_app/webhooks_controller.rb +5 -26
- data/app/views/shopify_app/partials/_button_styles.html.erb +41 -36
- data/app/views/shopify_app/partials/_card_styles.html.erb +3 -3
- data/app/views/shopify_app/partials/_empty_state_styles.html.erb +28 -59
- data/app/views/shopify_app/partials/_form_styles.html.erb +56 -0
- data/app/views/shopify_app/partials/_layout_styles.html.erb +16 -1
- data/app/views/shopify_app/partials/_typography_styles.html.erb +6 -6
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +2 -7
- data/app/views/shopify_app/sessions/new.html.erb +38 -110
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +12 -12
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +21 -22
- data/app/views/shopify_app/shared/post_redirect_to_auth_shopify.html.erb +13 -0
- data/app/views/shopify_app/shared/redirect.html.erb +2 -2
- data/config/locales/de.yml +11 -11
- data/config/locales/ja.yml +4 -4
- data/config/locales/nl.yml +2 -2
- data/config/locales/th.yml +4 -4
- data/config/locales/vi.yml +22 -0
- data/config/locales/zh-CN.yml +2 -2
- data/config/routes.rb +20 -12
- data/docs/Quickstart.md +19 -83
- data/docs/Releasing.md +18 -15
- data/docs/Troubleshooting.md +140 -5
- data/docs/Upgrading.md +247 -0
- data/docs/shopify_app/authentication.md +128 -0
- data/docs/shopify_app/content-security-policy.md +10 -0
- data/docs/shopify_app/engine.md +82 -0
- data/docs/shopify_app/generators.md +127 -0
- data/docs/shopify_app/handling-access-scopes-changes.md +24 -0
- data/docs/shopify_app/script-tags.md +28 -0
- data/docs/shopify_app/session-repository.md +88 -0
- data/docs/shopify_app/testing.md +38 -0
- data/docs/shopify_app/webhooks.md +72 -0
- data/karma.conf.js +1 -1
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +10 -9
- data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +1 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +4 -3
- data/lib/generators/shopify_app/add_webhook/add_webhook_generator.rb +15 -14
- data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb.tt +9 -1
- data/lib/generators/shopify_app/app_proxy_controller/app_proxy_controller_generator.rb +7 -6
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb +2 -1
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_route.rb +1 -1
- data/lib/generators/shopify_app/authenticated_controller/authenticated_controller_generator.rb +4 -4
- data/lib/generators/shopify_app/controllers/controllers_generator.rb +5 -4
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +27 -4
- data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +12 -2
- data/lib/generators/shopify_app/home_controller/templates/index.html.erb +74 -16
- data/lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb +16 -0
- data/lib/generators/shopify_app/install/install_generator.rb +52 -40
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +5 -2
- data/lib/generators/shopify_app/install/templates/flash_messages.js +0 -2
- data/lib/generators/shopify_app/install/templates/session_store.rb +2 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.js +1 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +43 -5
- data/lib/generators/shopify_app/install/templates/shopify_app_importmap.js +13 -0
- data/lib/generators/shopify_app/products_controller/products_controller_generator.rb +19 -0
- data/lib/generators/shopify_app/products_controller/templates/products_controller.rb +8 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb +4 -4
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake +1 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb +1 -1
- data/lib/generators/shopify_app/routes/routes_generator.rb +6 -5
- data/lib/generators/shopify_app/routes/templates/routes.rb +5 -5
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +35 -7
- data/lib/generators/shopify_app/shop_model/templates/db/migrate/add_shop_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +2 -1
- data/lib/generators/shopify_app/shopify_app_generator.rb +4 -3
- data/lib/generators/shopify_app/user_model/templates/db/migrate/add_user_access_scopes_column.erb +5 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +2 -1
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +35 -7
- data/lib/generators/shopify_app/views/views_generator.rb +5 -4
- data/lib/shopify_app/access_scopes/noop_strategy.rb +13 -0
- data/lib/shopify_app/access_scopes/shop_strategy.rb +24 -0
- data/lib/shopify_app/access_scopes/user_strategy.rb +41 -0
- data/lib/shopify_app/configuration.rb +58 -11
- data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +4 -4
- data/lib/shopify_app/controller_concerns/csrf_protection.rb +16 -0
- data/lib/shopify_app/controller_concerns/embedded_app.rb +6 -3
- data/lib/shopify_app/controller_concerns/ensure_billing.rb +243 -0
- data/lib/shopify_app/controller_concerns/frame_ancestors.rb +16 -0
- data/lib/shopify_app/controller_concerns/itp.rb +3 -3
- data/lib/shopify_app/controller_concerns/localization.rb +1 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +105 -90
- data/lib/shopify_app/controller_concerns/payload_verification.rb +25 -0
- data/lib/shopify_app/controller_concerns/redirect_for_embedded.rb +36 -0
- data/lib/shopify_app/controller_concerns/sanitized_params.rb +36 -0
- data/lib/shopify_app/controller_concerns/webhook_verification.rb +3 -18
- data/lib/shopify_app/engine.rb +26 -11
- data/lib/shopify_app/errors.rb +34 -0
- data/lib/shopify_app/jobs/scripttags_manager_job.rb +2 -2
- data/lib/shopify_app/jobs/webhooks_manager_job.rb +4 -5
- data/lib/shopify_app/managers/scripttags_manager.rb +12 -6
- data/lib/shopify_app/managers/webhooks_manager.rb +62 -42
- data/lib/shopify_app/middleware/jwt_middleware.rb +6 -3
- data/lib/shopify_app/session/in_memory_session_store.rb +2 -3
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +10 -7
- data/lib/shopify_app/session/in_memory_user_session_store.rb +10 -7
- data/lib/shopify_app/session/jwt.rb +19 -16
- data/lib/shopify_app/session/null_user_session_store.rb +2 -1
- data/lib/shopify_app/session/session_repository.rb +40 -2
- data/lib/shopify_app/session/session_storage.rb +4 -6
- data/lib/shopify_app/session/shop_session_storage.rb +6 -6
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +57 -0
- data/lib/shopify_app/session/user_session_storage.rb +20 -7
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +71 -0
- data/lib/shopify_app/test_helpers/all.rb +2 -1
- data/lib/shopify_app/test_helpers/webhook_verification_helper.rb +4 -3
- data/lib/shopify_app/utils.rb +14 -7
- data/lib/shopify_app/version.rb +2 -1
- data/lib/shopify_app.rb +52 -29
- data/package.json +7 -8
- data/service.yml +1 -5
- data/shopify_app.gemspec +22 -20
- data/translation.yml +1 -1
- data/yarn.lock +2173 -2206
- metadata +110 -56
- data/.github/ISSUE_TEMPLATE.md +0 -14
- data/.github/probots.yml +0 -2
- data/.travis.yml +0 -28
- data/config/locales/hi.yml +0 -23
- data/config/locales/ms.yml +0 -22
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/lib/generators/shopify_app/install/templates/omniauth.rb +0 -3
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +0 -20
- data/lib/generators/shopify_app/install/templates/user_agent.rb +0 -6
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +0 -34
- data/package-lock.json +0 -7245
data/docs/Upgrading.md
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
# Upgrading
|
2
|
+
|
3
|
+
This file documents important changes needed to upgrade your app's Shopify App version to a new major version.
|
4
|
+
|
5
|
+
#### Table of contents
|
6
|
+
|
7
|
+
[Upgrading to `v20.2.0`](#upgrading-to-v2020)
|
8
|
+
|
9
|
+
[Upgrading to `v20.1.0`](#upgrading-to-v2010)
|
10
|
+
|
11
|
+
[Upgrading to `v19.0.0`](#upgrading-to-v1900)
|
12
|
+
|
13
|
+
[Upgrading to `v18.1.2`](#upgrading-to-v1812)
|
14
|
+
|
15
|
+
[Upgrading to `v17.2.0`](#upgrading-to-v1720)
|
16
|
+
|
17
|
+
[Upgrading to `v13.0.0`](#upgrading-to-v1300)
|
18
|
+
|
19
|
+
[Upgrading to `v11.7.0`](#upgrading-to-v1170)
|
20
|
+
|
21
|
+
[Upgrading from `v8.6` to `v9.0.0`](#upgrading-from-v86-to-v900)
|
22
|
+
|
23
|
+
## Upgrading to `v20.2.0`
|
24
|
+
All custom errors defined inline within the `ShopifyApp` gem have been moved to `lib/shopify_app/errors.rb`.
|
25
|
+
|
26
|
+
- If you rescue any errors defined in this gem, you will need to rename them to match their new namespacing.
|
27
|
+
|
28
|
+
## Upgrading to `v20.1.0`
|
29
|
+
|
30
|
+
Note that the following steps are *optional* and only apply to **embedded** applications. However, they can improve the loading time of your embedded app at installation and re-auth.
|
31
|
+
|
32
|
+
- For embedded applications, update any controller that renders a full page reload (e.g: your home controller) to redirect using `Shopify::Auth.embedded_app_url`, if the `embedded` query argument is not present or does not equal `1`. Example [here](https://github.com/Shopify/shopify-app-template-ruby/pull/35/files#)
|
33
|
+
- If your app already has a frontend that uses App Bridge, this gem now supports using that to redirect out of the iframe before OAuth. Example [here](https://github.com/Shopify/shopify-frontend-template-react/blob/main/pages/ExitIframe.jsx)
|
34
|
+
- In your `shopify_app.rb` initializer, configure `.embedded_redirect_url` to the path of the route you added above.
|
35
|
+
- If you don't set this route, then the `shopify_app` gem will automatically load its own copy of App Bridge and perform this redirection without any additional configuration.
|
36
|
+
|
37
|
+
## Upgrading to `v19.0.0`
|
38
|
+
|
39
|
+
This update moves API authentication logic from this gem to the [`shopify_api`](https://github.com/Shopify/shopify-api-ruby)
|
40
|
+
gem.
|
41
|
+
|
42
|
+
### High-level process
|
43
|
+
|
44
|
+
- Delete `config/initializers/omniauth.rb` as apps no longer need to initialize `OmniAuth` directly.
|
45
|
+
- Delete `config/initializers/user_agent.rb` as `shopify_app` will set the right `User-Agent` header for interacting
|
46
|
+
with the Shopify API. If the app requires further information in the `User-Agent` header beyond what Shopify API
|
47
|
+
requires, specify this in the `ShopifyAPI::Context.user_agent_prefix` setting.
|
48
|
+
- Remove `allow_jwt_authentication=` and `allow_cookie_authentication=` invocations from
|
49
|
+
`config/initializers/shopify_app.rb` as the decision logic for which authentication method to use is now handled
|
50
|
+
internally by the `shopify_api` gem, using the `ShopifyAPI::Context.embedded_app` setting.
|
51
|
+
- `v19.0.0` updates the `shopify_api` dependency to `10.0.0`. This version of `shopify_api` has breaking changes. See
|
52
|
+
the documentation for addressing these breaking changes on GitHub [here](https://github.com/Shopify/shopify-api-ruby#breaking-change-notice-for-version-1000).
|
53
|
+
|
54
|
+
### Specific cases
|
55
|
+
|
56
|
+
#### Shopify user id in session
|
57
|
+
|
58
|
+
Previously, we set the entire app user object in the `session` object.
|
59
|
+
As of v19, since we no longer save the app user to the session (but only the shopify user id), we now store it as `session[:shopify_user_id]`. Please make sure to update any references to that object.
|
60
|
+
|
61
|
+
#### Webhook Jobs
|
62
|
+
|
63
|
+
Add a new `handle` method to existing webhook jobs to go through the updated `shopify_api` gem.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class MyWebhookJob < ActiveJob::Base
|
67
|
+
extend ShopifyAPI::Webhooks::Handler
|
68
|
+
|
69
|
+
class << self
|
70
|
+
# new handle function
|
71
|
+
def handle(topic:, shop:, body:)
|
72
|
+
# delegate to pre-existing perform_later function
|
73
|
+
perform_later(topic: topic, shop_domain: shop, webhook: body)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# original perform function
|
78
|
+
def perform(topic:, shop_domain:, webhook:)
|
79
|
+
# ...
|
80
|
+
```
|
81
|
+
|
82
|
+
#### Temporary sessions
|
83
|
+
|
84
|
+
The new `shopify_api` gem offers a utility to temporarily create sessions for interacting with the API within a block.
|
85
|
+
This is useful for interacting with the Shopify API outside of the context of a subclass of `AuthenticatedController`.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
ShopifyAPI::Auth::Session.temp(shop: shop_domain, access_token: shop_token) do |session|
|
89
|
+
# make invocations to the API
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
Within a subclass of `AuthenticatedController`, the `current_shopify_session` function will return the current active
|
94
|
+
Shopify API session, or `nil` if no such session is available.
|
95
|
+
|
96
|
+
#### Setting up `ShopifyAPI::Context`
|
97
|
+
|
98
|
+
The `shopify_app` initializer must configure the `ShopifyAPI::Context`. The Rails generator will
|
99
|
+
generate a block in the `shopify_app` initializer. To do so manually, ensure the following is
|
100
|
+
part of the `after_initialize` block in `shopify_app.rb`.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Rails.application.config.after_initialize do
|
104
|
+
if ShopifyApp.configuration.api_key.present? && ShopifyApp.configuration.secret.present?
|
105
|
+
ShopifyAPI::Context.setup(
|
106
|
+
api_key: ShopifyApp.configuration.api_key,
|
107
|
+
api_secret_key: ShopifyApp.configuration.secret,
|
108
|
+
old_api_secret_key: ShopifyApp.configuration.old_secret,
|
109
|
+
api_version: ShopifyApp.configuration.api_version,
|
110
|
+
host_name: URI(ENV.fetch('HOST', '')).host || '',
|
111
|
+
scope: ShopifyApp.configuration.scope,
|
112
|
+
is_private: !ENV.fetch('SHOPIFY_APP_PRIVATE_SHOP', '').empty?,
|
113
|
+
is_embedded: ShopifyApp.configuration.embedded_app,
|
114
|
+
session_storage: ShopifyApp::SessionRepository,
|
115
|
+
logger: Rails.logger,
|
116
|
+
private_shop: ENV.fetch('SHOPIFY_APP_PRIVATE_SHOP', nil),
|
117
|
+
user_agent_prefix: "ShopifyApp/#{ShopifyApp::VERSION}"
|
118
|
+
)
|
119
|
+
|
120
|
+
ShopifyApp::WebhooksManager.add_registrations
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
## Upgrading to `v18.1.2`
|
126
|
+
|
127
|
+
Version 18.1.2 replaces the deprecated EASDK redirect with an App Bridge 2 redirect when attempting to break out of an iframe. This happens when an app is installed, requires new access scopes, or re-authentication because the login session is expired.
|
128
|
+
|
129
|
+
## Upgrading to `v17.2.0`
|
130
|
+
|
131
|
+
### Different SameSite cookie attribute behaviour
|
132
|
+
|
133
|
+
To support Rails `v6.1`, the [`SameSiteCookieMiddleware`](/lib/shopify_app/middleware/same_site_cookie_middleware.rb) was updated to configure cookies to `SameSite=None` if the app is embedded. Before this release, cookies were configured to `SameSite=None` only if this attribute had not previously been set before.
|
134
|
+
|
135
|
+
```diff
|
136
|
+
# same_site_cookie_middleware.rb
|
137
|
+
- cookie << '; SameSite=None' unless cookie =~ /;\s*samesite=/i
|
138
|
+
+ cookie << '; SameSite=None' if ShopifyApp.configuration.embedded_app?
|
139
|
+
```
|
140
|
+
|
141
|
+
By default, Rails `v6.1` configures `SameSite=Lax` on all cookies that don't specify this attribute.
|
142
|
+
|
143
|
+
## Upgrading to `v13.0.0`
|
144
|
+
|
145
|
+
Version 13.0.0 adds the ability to use both user and shop sessions, concurrently. This however involved a large
|
146
|
+
change to how session stores work. Here are the steps to migrate to 13.x
|
147
|
+
|
148
|
+
### Changes to `config/initializers/shopify_app.rb`
|
149
|
+
|
150
|
+
- _REMOVE_ `config.per_user_tokens = [true|false]` this is no longer needed
|
151
|
+
- _CHANGE_ `config.session_repository = 'Shop'` To `config.shop_session_repository = 'Shop'`
|
152
|
+
- _ADD (optional)_ User Session Storage `config.user_session_repository = 'User'`
|
153
|
+
|
154
|
+
### Shop Model Changes (normally `app/models/shop.rb`)
|
155
|
+
|
156
|
+
- _CHANGE_ `include ShopifyApp::SessionStorage` to `include ShopifyApp::ShopSessionStorage`
|
157
|
+
|
158
|
+
### Changes to the @shop_session instance variable (normally in `app/controllers/*.rb`)
|
159
|
+
|
160
|
+
- _CHANGE_ if you are using shop sessions, `@shop_session` will need to be changed to `@current_shopify_session`.
|
161
|
+
|
162
|
+
### Changes to Rails `session`
|
163
|
+
|
164
|
+
- _CHANGE_ `session[:shopify]` is no longer set. Use `session[:user_id]` if your app uses user based tokens, or `session[:shop_id]` if your app uses shop based tokens.
|
165
|
+
|
166
|
+
### Changes to `ShopifyApp::LoginProtection`
|
167
|
+
|
168
|
+
`ShopifyApp::LoginProtection`
|
169
|
+
|
170
|
+
- CHANGE if you are using `ShopifyApp::LoginProtection#shopify_session` in your code, it will need to be
|
171
|
+
changed to `ShopifyApp::LoginProtection#activate_shopify_session`
|
172
|
+
- CHANGE if you are using `ShopifyApp::LoginProtection#clear_shop_session` in your code, it will need to be
|
173
|
+
changed to `ShopifyApp::LoginProtection#clear_shopify_session`
|
174
|
+
|
175
|
+
### Notes
|
176
|
+
|
177
|
+
You do not need a user model; a shop session is fine for most applications.
|
178
|
+
|
179
|
+
---
|
180
|
+
|
181
|
+
## Upgrading to `v11.7.0`
|
182
|
+
|
183
|
+
### Session storage method signature breaking change
|
184
|
+
|
185
|
+
If you override `def self.store(auth_session)` method in your session storage model (e.g. Shop), the method signature has changed to `def self.store(auth_session, *args)` in order to support user-based token storage. Please update your method signature to include the second argument.
|
186
|
+
|
187
|
+
---
|
188
|
+
|
189
|
+
## Upgrading from `v8.6` to `v9.0.0`
|
190
|
+
|
191
|
+
### Configuration change
|
192
|
+
|
193
|
+
Add an API version configuration in `config/initializers/shopify_app.rb`
|
194
|
+
Set this to the version you want to run against by default. See [Shopify API docs](https://help.shopify.com/api/versioning) for versions available.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
config.api_version = '2019-04'
|
198
|
+
```
|
199
|
+
|
200
|
+
### Session storage change
|
201
|
+
|
202
|
+
You will need to add an `api_version` method to your session storage object. The default implementation for this is.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
def api_version
|
206
|
+
ShopifyApp.configuration.api_version
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
### Generated file change
|
211
|
+
|
212
|
+
`embedded_app.html.erb` the usage of `shop_session.url` needs to be changed to `shop_session.domain`
|
213
|
+
|
214
|
+
```erb
|
215
|
+
<script type="text/javascript">
|
216
|
+
ShopifyApp.init({
|
217
|
+
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
218
|
+
|
219
|
+
shopOrigin: "<%= "https://#{ @shop_session.url }" if @shop_session %>",
|
220
|
+
|
221
|
+
debug: false,
|
222
|
+
forceRedirect: true
|
223
|
+
});
|
224
|
+
</script>
|
225
|
+
```
|
226
|
+
|
227
|
+
is changed to
|
228
|
+
|
229
|
+
```erb
|
230
|
+
<script type="text/javascript">
|
231
|
+
ShopifyApp.init({
|
232
|
+
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
233
|
+
|
234
|
+
shopOrigin: "<%= "https://#{ @shop_session.domain }" if @shop_session %>",
|
235
|
+
|
236
|
+
debug: false,
|
237
|
+
forceRedirect: true
|
238
|
+
});
|
239
|
+
</script>
|
240
|
+
```
|
241
|
+
|
242
|
+
### ShopifyAPI changes
|
243
|
+
|
244
|
+
You will need to also follow the ShopifyAPI [upgrade guide](https://github.com/Shopify/shopify-api-ruby/blob/master/README.md#-breaking-change-notice-for-version-700-) to ensure your app is ready to work with API versioning.
|
245
|
+
|
246
|
+
[dashboard]: https://partners.shopify.com
|
247
|
+
[app-bridge]: https://shopify.dev/apps/tools/app-bridge
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Authentication
|
2
|
+
|
3
|
+
The Shopify App gem implements [OAuth 2.0](https://shopify.dev/tutorials/authenticate-with-oauth) to get [access tokens](https://shopify.dev/concepts/about-apis/authentication#api-access-modes). These are used to authenticate requests made by the app to the Shopify API.
|
4
|
+
|
5
|
+
By default, the gem generates an embedded app frontend that uses [Shopify App Bridge](https://shopify.dev/tools/app-bridge) to fetch [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens). Session tokens are used by the embedded app to make authenticated requests to the app backend.
|
6
|
+
|
7
|
+
See [*Authenticate an embedded app using session tokens*](https://shopify.dev/tutorials/authenticate-your-app-using-session-tokens) to learn more.
|
8
|
+
|
9
|
+
> ⚠️ Be sure you understand the differences between the types of authentication schemes before reading this guide.
|
10
|
+
|
11
|
+
#### Table of contents
|
12
|
+
|
13
|
+
[OAuth callback](#oauth-callback)
|
14
|
+
|
15
|
+
[Run jobs after the OAuth flow](#run-jobs-after-the-oauth-flow)
|
16
|
+
|
17
|
+
[Rotate API credentials](#rotate-api-credentials)
|
18
|
+
|
19
|
+
[Available authentication mixins](#available-authentication-mixins)
|
20
|
+
* [`ShopifyApp::Authenticated`](#shopifyappauthenticated)
|
21
|
+
* [`ShopifyApp::EnsureAuthenticatedLinks`](#shopifyappensureauthenticatedlinks)
|
22
|
+
|
23
|
+
## OAuth callback
|
24
|
+
|
25
|
+
>️ **Note:** In Shopify App version 8.4.0, we have extracted the callback logic in its own controller. If you are upgrading from a version older than 8.4.0 the callback action and related helper methods were defined in `ShopifyApp::SessionsController` ==> you will have to extend `ShopifyApp::CallbackController` instead and port your logic to the new controller.
|
26
|
+
|
27
|
+
Upon completing the OAuth flow, Shopify calls the app at the `callback_path`. If the app needs to do some extra work, it can define and configure the route to a custom callback controller, inheriting from `ShopifyApp::CallbackController` and hook into or override any of the defined helper methods. The default callback controller already provides the following behaviour:
|
28
|
+
* Logging into the shop and resetting the session
|
29
|
+
* [Installing Webhooks](/docs/shopify_app/webhooks.md)
|
30
|
+
* [Setting Scripttags](/docs/shopify_app/script-tags.md)
|
31
|
+
* [Run jobs after the OAuth flow](#run-jobs-after-the-oauth-flow)
|
32
|
+
* Redirecting to the return address
|
33
|
+
|
34
|
+
## Run jobs after the OAuth flow
|
35
|
+
|
36
|
+
See [`ShopifyApp::AfterAuthenticateJob`](/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb).
|
37
|
+
|
38
|
+
If your app needs to perform specific actions after the user is authenticated successfully (i.e. every time a new session is created), ShopifyApp can queue or run a job of your choosing (note that we already provide support for automatically creating Webhooks and Scripttags). To configure the after authenticate job, update your initializer as follows:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
ShopifyApp.configure do |config|
|
42
|
+
config.after_authenticate_job = { job: "Shopify::AfterAuthenticateJob" }
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
The job can be configured as either a class or a class name string.
|
47
|
+
|
48
|
+
If you need the job to run synchronously add the `inline` flag:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
ShopifyApp.configure do |config|
|
52
|
+
config.after_authenticate_job = { job: Shopify::AfterAuthenticateJob, inline: true }
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
We've also provided a generator which creates a skeleton job and updates the initializer for you:
|
57
|
+
|
58
|
+
```
|
59
|
+
bin/rails g shopify_app:add_after_authenticate_job
|
60
|
+
```
|
61
|
+
|
62
|
+
If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
|
63
|
+
|
64
|
+
## Rotate API credentials
|
65
|
+
|
66
|
+
If your Shopify secret key is leaked, you can use the RotateShopifyTokenJob to perform [API Credential Rotation](https://help.shopify.com/en/api/getting-started/authentication/oauth/api-credential-rotation).
|
67
|
+
|
68
|
+
Before running the job, you'll need to generate a new secret key from your Shopify Partner dashboard, and update the `/config/initializers/shopify_app.rb` to hold your new and old secret keys:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
config.secret = Rails.application.secrets.shopify_secret
|
72
|
+
config.old_secret = Rails.application.secrets.old_shopify_secret
|
73
|
+
```
|
74
|
+
|
75
|
+
We've provided a generator which creates the job and an example rake task:
|
76
|
+
|
77
|
+
```sh
|
78
|
+
bin/rails g shopify_app:rotate_shopify_token_job
|
79
|
+
```
|
80
|
+
|
81
|
+
The generated rake task will be found at `lib/tasks/shopify/rotate_shopify_token.rake` and is provided strictly for example purposes. It might not work with your application out of the box without some configuration.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
85
|
+
```
|
86
|
+
|
87
|
+
> **Note:** If you are updating `shopify_app` from a version prior to 8.4.2 (and do not wish to run the default/install generator again), you will need to add [the following line](https://github.com/Shopify/shopify_app/blob/4f7e6cca2a472d8f7af44b938bd0fcafe4d8e88a/lib/generators/shopify_app/install/templates/shopify_provider.rb#L18) to `config/initializers/omniauth.rb`:
|
88
|
+
|
89
|
+
## Available authentication mixins
|
90
|
+
|
91
|
+
### `ShopifyApp::Authenticated`
|
92
|
+
|
93
|
+
The engine provides a [`ShopifyApp::Authenticated`](/app/controllers/concerns/shopify_app/authenticated.rb) concern which should be included in any controller that is intended to be behind Shopify OAuth. It adds `before_action`s to ensure that the user is authenticated and will redirect to the Shopify login page if not. It is best practice to include this concern in a base controller inheriting from your `ApplicationController`, from which all controllers that require Shopify authentication inherit.
|
94
|
+
|
95
|
+
*Example:*
|
96
|
+
|
97
|
+
```rb
|
98
|
+
class AuthenticatedController < ApplicationController
|
99
|
+
include ShopifyApp::Authenticated
|
100
|
+
end
|
101
|
+
|
102
|
+
class ApiController < AuthenticatedController
|
103
|
+
# Actions in this controller are protected
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
For backwards compatibility, the engine still provides a controller called `ShopifyApp::AuthenticatedController` which includes the `ShopifyApp::Authenticated` concern. Note that it inherits directly from `ActionController::Base`, so you will not be able to share functionality between it and your application's `ApplicationController`.
|
108
|
+
|
109
|
+
#### Embedded apps and `ShopifyApp::Authenticated`
|
110
|
+
|
111
|
+
Embedded Shopify Admin apps can only use the `ShopifyApp::Authenticated` controller concern *if* the requests originate from App Bridge's `authenticatedFetch` method. Those who include this concern in the `HomeController` or some other embedded controller will see what looks like an OAuth redirect loop as the `ShopifyApp::Authenticated` concern will be fighting with the App Bridge. For more details on how to handle embedded sessions, refer to [the session token documentation](https://shopify.dev/apps/auth/oauth/session-tokens).
|
112
|
+
|
113
|
+
### `ShopifyApp::EnsureAuthenticatedLinks`
|
114
|
+
|
115
|
+
The [`ShopifyApp::EnsureAuthenticatedLinks`](/app/controllers/concerns/shopify_app/ensure_authenticated_links.rb) concern helps authenticate users that access protected pages of your app directly.
|
116
|
+
|
117
|
+
Include this concern in your app's `AuthenticatedController` if your app uses session tokens with [Turbolinks](https://github.com/turbolinks/turbolinks). It adds a `before_action` filter that detects whether a session token is present or not. If a session token is not found, the user is redirected to your app's splash page path (`root_path`) along with `return_to` and `shop` parameters.
|
118
|
+
|
119
|
+
*Example:*
|
120
|
+
|
121
|
+
```rb
|
122
|
+
class AuthenticatedController < ApplicationController
|
123
|
+
include ShopifyApp::EnsureAuthenticatedLinks
|
124
|
+
include ShopifyApp::Authenticated
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
See [Authenticate server-side rendered embedded apps using Rails and Turbolinks](https://shopify.dev/tutorials/authenticate-server-side-rendered-embedded-apps-using-rails-and-turbolinks) for more information.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Content Security Policy Header
|
2
|
+
|
3
|
+
Shopify App [handles Rails' configuration](https://edgeguides.rubyonrails.org/security.html#content-security-policy-header) for [Content-Security-Policy Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) when the `ShopifyApp::FrameAncestors` controller concern is included in controllers. This is tyipcally done by including the [`ShopifyApp::Authenticated`](https://github.com/Shopify/shopify_app/blob/ed41165ca9598d2c9d514487365192f22b5eb096/app/controllers/concerns/shopify_app/authenticated.rb) controller concern rather that directly including it.
|
4
|
+
|
5
|
+
## Included Domains
|
6
|
+
|
7
|
+
For actions that include the `ShopifyApp::FrameAncestors` controller concern, the following hosts are added to the Content-Security-Policy header as [per the store requirements](https://shopify.dev/apps/store/security/iframe-protection#embedded-apps):
|
8
|
+
|
9
|
+
1. [`current_shopify_domain`](https://github.com/Shopify/shopify_app/blob/ed41165ca9598d2c9d514487365192f22b5eb096/app/controllers/concerns/shopify_app/require_known_shop.rb#L13) || `"*.myshopify.com"` if current shopify domain isn't present
|
10
|
+
2. "https://admin.shopify.com"
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Engine
|
2
|
+
|
3
|
+
#### Table of contents
|
4
|
+
|
5
|
+
[Customize the app login URL](#customize-the-app-login-url)
|
6
|
+
|
7
|
+
[Mount the Shopify App engine at nested routes](#mount-the-shopify-app-engine-at-nested-routes)
|
8
|
+
|
9
|
+
[Verify HTTP requests sent via an app proxy](#verify-http-requests-sent-via-an-app-proxy)
|
10
|
+
* [Recommended usage of `ShopifyApp::AppProxyVerification`](#recommended-usage-of-shopifyappappproxyverification)
|
11
|
+
|
12
|
+
## Customize the app login URL
|
13
|
+
|
14
|
+
While you can customize the login view by creating a `/app/views/shopify_app/sessions/new.html.erb` file, you may also want to customize the URL entirely. You can modify your `shopify_app.rb` initializer to provide a custom `login_url` e.g.:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
ShopifyApp.configure do |config|
|
18
|
+
config.login_url = 'https://example.com/nested/login'
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
## Mount the Shopify App engine at nested routes
|
23
|
+
|
24
|
+
The engine may also be mounted at a nested route, for example:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
mount ShopifyApp::Engine, at: '/nested'
|
28
|
+
```
|
29
|
+
|
30
|
+
This will create the Shopify engine routes under the specified subpath. You'll also need to make some updates to your `shopify_app.rb` and `omniauth.rb` initializers. First, update the shopify_app initializer to include a custom `root_url` e.g.:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
ShopifyApp.configure do |config|
|
34
|
+
config.root_url = '/nested'
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
then update the omniauth initializer to include a custom `callback_path` e.g.:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
provider :shopify,
|
42
|
+
ShopifyApp.configuration.api_key,
|
43
|
+
ShopifyApp.configuration.secret,
|
44
|
+
scope: ShopifyApp.configuration.scope,
|
45
|
+
callback_path: '/nested/auth/shopify/callback'
|
46
|
+
```
|
47
|
+
|
48
|
+
You may also need to change your `config/routes.rb` to render a view for `/nested`, since this is what will be rendered in the Shopify Admin of any shops that have installed your app. The engine itself doesn't have a view for this, so you'll need something like this:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# config/routes.rb
|
52
|
+
Rails.application.routes.draw do
|
53
|
+
root :to => 'something_else#index'
|
54
|
+
get "/nested", to: "home#index"
|
55
|
+
mount ShopifyApp::Engine, at: '/nested'
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Finally, note that if you do this, to add your app to a store, you must navigate to `/nested` in order to render the `Enter your shop domain to log in or install this app.` UI.
|
60
|
+
|
61
|
+
## Verify HTTP requests sent via an app proxy
|
62
|
+
|
63
|
+
See [`ShopifyApp::AppProxyVerification`](/lib/shopify_app/controller_concerns/app_proxy_verification.rb).
|
64
|
+
|
65
|
+
The engine provides a mixin for verifying incoming HTTP requests sent via an App Proxy. Any controller that `include`s `ShopifyApp::AppProxyVerification` will verify that each request has a valid `signature` query parameter that is calculated using the other query parameters and the app's shared secret.
|
66
|
+
|
67
|
+
### Recommended usage of `ShopifyApp::AppProxyVerification`
|
68
|
+
|
69
|
+
The App Proxy Controller Generator automatically adds the mixin to the generated app_proxy_controller.rb
|
70
|
+
Additional controllers for resources within the App_Proxy namespace, will need to include the mixin like so:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# app/controllers/app_proxy/reviews_controller.rb
|
74
|
+
class ReviewsController < ApplicationController
|
75
|
+
include ShopifyApp::AppProxyVerification
|
76
|
+
# ...
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Create your app proxy URL in the [Shopify Partners dashboard](https://partners.shopify.com/organizations), making sure to point it to `https://example.com/app_proxy`.
|
81
|
+
|
82
|
+
![Creating an App Proxy](/images/app-proxy-screenshot.png)
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# Generators
|
2
|
+
|
3
|
+
> Listed below are the generators currently offered by the Shopify App gem. To learn more about how this gem creates an embedded app, start with the [default Shopify App generator](#-environment-rails-generate-shopify_app).
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
#### `$ [environment] rails generate shopify_app`
|
8
|
+
|
9
|
+
The default generator will run the [`install`](#-rails-generate-shopify_appinstall-flags), [`shop_model`](#-rails-generate-shopify_appshop_model), [`authenticated_controller`](#-rails-generate-shopify_appauthenticated_controller), and [`home_controller`](#-rails-generate-shopify_apphome_controller-flags) generators. This is the recommended way to start a new app from scratch.
|
10
|
+
|
11
|
+
##### Environment
|
12
|
+
|
13
|
+
###### `SHOPIFY_APP_DISABLE_WEBPACKER`
|
14
|
+
|
15
|
+
**[Optional]** Specify this environment variable if your app uses sprockets with Rails 6 or to generate a Shopify App without webpacker.
|
16
|
+
|
17
|
+
*Example:*
|
18
|
+
|
19
|
+
Run:
|
20
|
+
|
21
|
+
```terminal
|
22
|
+
$ SHOPIFY_APP_DISABLE_WEBPACKER=1 rails generate shopify_app
|
23
|
+
```
|
24
|
+
|
25
|
+
Add the following code to your ShopifyApp configuration block:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
ShopifyApp.configure do |config|
|
29
|
+
config.disable_webpacker = true
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
---
|
34
|
+
|
35
|
+
#### `$ rails generate shopify_app:install [flags]`
|
36
|
+
|
37
|
+
This generator adds ShopifyApp and the required initializers to the host Rails application. You can update any of these settings later.
|
38
|
+
|
39
|
+
##### Flags
|
40
|
+
|
41
|
+
###### `--application_name`
|
42
|
+
|
43
|
+
The name of your app. The flag can be supplied with or without double-quotes.
|
44
|
+
|
45
|
+
*Example:* `--application_name "My Shopify App"`
|
46
|
+
|
47
|
+
###### `--scope`
|
48
|
+
|
49
|
+
The [OAuth access scope(s)](https://shopify.dev/docs/admin-api/access-scopes) required by your app. Delimit multiple access scopes using a comma-space. The flag can be supplied with or without double-quotes.
|
50
|
+
|
51
|
+
*Example:* `--scope read_products, write_orders`
|
52
|
+
|
53
|
+
*Example:* `--scope "read_products, write_orders"`
|
54
|
+
|
55
|
+
###### `--embedded`
|
56
|
+
|
57
|
+
Specify whether the app is an embedded app. Apps are embedded by default.
|
58
|
+
|
59
|
+
*Example:* `--embedded false`
|
60
|
+
|
61
|
+
###### `--with-cookie-authentication`
|
62
|
+
|
63
|
+
**[Not recommended]** Specify whether the app uses cookies to authenticate. By default, the app is configured to use [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens).
|
64
|
+
|
65
|
+
*Example:* `--with-cookie-authentication true`
|
66
|
+
|
67
|
+
---
|
68
|
+
|
69
|
+
#### `$ rails generate shopify_app:shop_model`
|
70
|
+
|
71
|
+
This generator creates a `Shop` model and a migration to store shop installation records. See [*Shop-based token strategy*](/docs/shopify_app/session-repository.md#shop-based-token-storage) to learn more.
|
72
|
+
|
73
|
+
---
|
74
|
+
|
75
|
+
#### `$ rails generate shopify_app:user_model`
|
76
|
+
|
77
|
+
This generator creates a `User` model and a migration to store user records. See [*User-based token strategy*](/docs/shopify_app/session-repository.md#user-based-token-storage) to learn more.
|
78
|
+
|
79
|
+
---
|
80
|
+
|
81
|
+
#### `$ rails generate shopify_app:authenticated_controller`
|
82
|
+
|
83
|
+
This generator creates a sample authenticated controller. By default, inheriting from this controller protects your app controllers using session tokens. See [*Authentication*](/docs/shopify_app/authentication.md) to learn more.
|
84
|
+
|
85
|
+
---
|
86
|
+
|
87
|
+
#### `$ rails generate shopify_app:home_controller [flags]`
|
88
|
+
|
89
|
+
This generator creates a sample home controller with a view that displays a shop's products. This generator also runs the [`products_controller`](#-rails-generate-shopify_appproducts_controller) generator.
|
90
|
+
|
91
|
+
##### Flags
|
92
|
+
|
93
|
+
###### `--with-cookie-authentication`
|
94
|
+
|
95
|
+
**[Not recommended]** This flag generates an authenticated home controller. Use this flag only if your app uses cookies to authenticate. By default, the home controller is unauthenticated.
|
96
|
+
|
97
|
+
---
|
98
|
+
|
99
|
+
#### `$ rails generate shopify_app:products_controller`
|
100
|
+
|
101
|
+
This generator creates a sample products API controller to fetch products using the Shopify REST API.
|
102
|
+
|
103
|
+
---
|
104
|
+
|
105
|
+
#### `$ rails generate shopify_app:add_after_authenticate_job`
|
106
|
+
|
107
|
+
**[Optional]** This generator creates a skeleton job that runs after the OAuth authorization flow. See [*Run jobs after the OAuth flow*](/docs/shopify_app/authentication.md#run-jobs-after-the-oauth-flow) for more information.
|
108
|
+
|
109
|
+
---
|
110
|
+
|
111
|
+
#### `$ rails generate shopify_app:app_proxy_controller`
|
112
|
+
|
113
|
+
**[Optional]** This generator creates the app proxy controller to handle proxy requests to the app from your shop storefront. It also modifies 'config/routes.rb' with a namespace route and creates a sample view that displays current shop information using the LiquidAPI. See [*Verify HTTP requests sent via an app proxy*](/docs/shopify_app/engine.md#verify-http-requests-sent-via-an-app-proxy) for more information.
|
114
|
+
|
115
|
+
---
|
116
|
+
|
117
|
+
#### `$ rails generate shopify_app:marketing_activity_extension`
|
118
|
+
|
119
|
+
**[Optional]** This generator creates a controller with the endpoints required to build a [marketing activities extension](https://shopify.dev/docs/marketing-activities). The extension is generated with the base URL `/marketing_activities`. This URL would need to be configured in the Shopify Partners dashboard.
|
120
|
+
|
121
|
+
---
|
122
|
+
|
123
|
+
#### `$ rails generate shopify_app:controllers`
|
124
|
+
|
125
|
+
**[Optional]** This generator is for your convenience. Run this generator if you would like to override code that is part of the Shopify App Rails engine.
|
126
|
+
|
127
|
+
*Example:* The Shopify App Rails engine provides a sample [`SessionsController`](/app/controllers/shopify_app/sessions_controller.rb). Running this generator copies this controller to your app so you can begin extending it. Routes and views follow the same pattern.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Handling changes in access scopes
|
2
|
+
## Updating the list of scopes the app requests
|
3
|
+
|
4
|
+
Your app specifies the [access scopes](https://shopify.dev/api/usage/access-scopes) it requires in the Shopify App initializer, located at`config/initializers/shopify_app.rb`. To modify this list, update the comma-delimited configuration option:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
config.scope = "read_products,write_discounts"
|
8
|
+
```
|
9
|
+
|
10
|
+
## Requesting new scopes from merchants
|
11
|
+
|
12
|
+
The Shopify App gem will automatically request new scopes from merchants for both shop/offline and user/online tokens. To enable your app to reauth via OAuth on scope changes, you can set the following configuration flag in your `config/initializers/shopify_app.rb`:
|
13
|
+
```ruby
|
14
|
+
config.reauth_on_access_scope_changes = true
|
15
|
+
```
|
16
|
+
|
17
|
+
## ShopAccessScopesVerification
|
18
|
+
The `ShopifyApp::ShopAccessScopesVerification` concern helps merchants grant new access scopes requested by the app. The concern compares the current access scopes granted by the shop and compares them with the scopes requested by the app. If there is a mismatch in configuration, the merchant is redirected to login via OAuth and grant the net new scopes.
|
19
|
+
|
20
|
+
To activate the `ShopAccessScopesVerification` for a controller add `include ShopifyApp::ShopAccessScopesVerification`:
|
21
|
+
```ruby
|
22
|
+
class HomeController < AuthenticatedController
|
23
|
+
include ShopifyApp::ShopAccessScopesVerification
|
24
|
+
```
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# ScriptTags
|
2
|
+
|
3
|
+
#### Table of contents
|
4
|
+
|
5
|
+
[Manage ScriptTags using the Shopify App initializer](#manage-scripttags-using-the-shopify-app-initializer)
|
6
|
+
|
7
|
+
## Manage ScriptTags using the Shopify App initializer
|
8
|
+
|
9
|
+
As with webhooks, ShopifyApp can manage your app's [ScriptTags](https://shopify-dev-staging.shopifycloud.com/docs/admin-api/graphql/reference/online-store/scripttag) for you by setting which scripttags you require in the initializer:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
ShopifyApp.configure do |config|
|
13
|
+
config.scripttags = [
|
14
|
+
{event:'onload', src: 'https://example.com/fancy.js'},
|
15
|
+
{event:'onload', src: ->(domain) { dynamic_tag_url(domain) } }
|
16
|
+
]
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
You also need to have write_script_tags permission in the config scope in order to add script tags automatically:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
config.scope = '... , write_script_tags'
|
24
|
+
```
|
25
|
+
|
26
|
+
Scripttags are created in the same way as the [Webhooks](/docs/shopify_app/webhooks.md), with a background job which will create the required scripttags.
|
27
|
+
|
28
|
+
If `src` responds to `call` its return value will be used as the scripttag's source. It will be called on scripttag creation and deletion.
|