shopify_app 22.0.1 → 22.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/workflows/rubocop.yml +1 -2
- data/.rubocop.yml +0 -1
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +20 -17
- data/README.md +38 -0
- data/app/controllers/concerns/shopify_app/ensure_has_session.rb +11 -5
- data/app/controllers/concerns/shopify_app/ensure_installed.rb +8 -2
- data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +5 -1
- data/app/controllers/shopify_app/callback_controller.rb +10 -1
- data/app/controllers/shopify_app/sessions_controller.rb +24 -4
- data/app/views/shopify_app/layouts/app_bridge.html.erb +17 -0
- data/app/views/shopify_app/sessions/patch_shopify_id_token.html.erb +0 -0
- data/config/routes.rb +1 -0
- data/docs/Troubleshooting.md +0 -23
- data/docs/Upgrading.md +25 -0
- data/docs/shopify_app/authentication.md +105 -20
- data/docs/shopify_app/sessions.md +110 -14
- data/docs/shopify_app/webhooks.md +1 -1
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +2 -0
- data/lib/shopify_app/admin_api/with_token_refetch.rb +28 -0
- data/lib/shopify_app/auth/post_authenticate_tasks.rb +48 -0
- data/lib/shopify_app/auth/token_exchange.rb +73 -0
- data/lib/shopify_app/configuration.rb +54 -3
- data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +1 -1
- data/lib/shopify_app/controller_concerns/embedded_app.rb +27 -0
- data/lib/shopify_app/controller_concerns/ensure_billing.rb +11 -3
- data/lib/shopify_app/controller_concerns/login_protection.rb +8 -23
- data/lib/shopify_app/controller_concerns/redirect_for_embedded.rb +5 -0
- data/lib/shopify_app/controller_concerns/token_exchange.rb +111 -0
- data/lib/shopify_app/controller_concerns/with_shopify_id_token.rb +41 -0
- data/lib/shopify_app/middleware/jwt_middleware.rb +13 -9
- data/lib/shopify_app/session/jwt.rb +9 -0
- data/lib/shopify_app/version.rb +1 -1
- data/lib/shopify_app.rb +9 -0
- data/package.json +1 -1
- data/shopify_app.gemspec +1 -1
- data/yarn.lock +3 -3
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e3a66e5b90c252c2d65a607911157a50a2d43ac799a70ef61bb5efaeab65013
|
4
|
+
data.tar.gz: 9c145d34b0c9a2f7f587ea2653d660ee7477f90f1348461e52c3dd84c6fc8c6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca6a9990ca94f975da2139e2e9ca4d85a9e967959e12cb08c2419d5614001b1245f292bff1916f2dfd45002a421a0a65b337148b917e4b56d6406e344c27e456
|
7
|
+
data.tar.gz: 2475faa54148b72d0764e29f101c4f6829f47d049cfcd2b800730a4fa1e6bfe35cf3e26f806366174b9e7a589e7a09143b0a4f9ef20cdbceb2e007b357bc63f3
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,36 @@
|
|
1
1
|
Unreleased
|
2
2
|
----------
|
3
3
|
|
4
|
+
22.2.0 (May 2,2024)
|
5
|
+
----------
|
6
|
+
* Add new zero redirect authorization strategy - `Token Exchange`.
|
7
|
+
- This strategy replaces the existing OAuth flow for embedded apps and remove the redirects that were previously necessary to complete OAuth.
|
8
|
+
See ["New embedded app authorization strategy"](/README.md/#new-embedded-app-authorization-strategy) for how to enable this feature.
|
9
|
+
- Related PRs: [#1817](https://github.com/Shopify/shopify_app/pull/1817),
|
10
|
+
[#1818](https://github.com/Shopify/shopify_app/pull/1818),
|
11
|
+
[#1819](https://github.com/Shopify/shopify_app/pull/1819),
|
12
|
+
[#1821](https://github.com/Shopify/shopify_app/pull/1821),
|
13
|
+
[#1822](https://github.com/Shopify/shopify_app/pull/1822),
|
14
|
+
[#1823](https://github.com/Shopify/shopify_app/pull/1823),
|
15
|
+
[#1832](https://github.com/Shopify/shopify_app/pull/1832),
|
16
|
+
[#1833](https://github.com/Shopify/shopify_app/pull/1833),
|
17
|
+
[#1834](https://github.com/Shopify/shopify_app/pull/1834),
|
18
|
+
[#1836](https://github.com/Shopify/shopify_app/pull/1836),
|
19
|
+
* Bumps `shopify_api` to `14.3.0` [1832](https://github.com/Shopify/shopify_app/pull/1832)
|
20
|
+
* Support `id_token` from URL param [1832](https://github.com/Shopify/shopify_app/pull/1832)
|
21
|
+
* Extracted controller concern `WithShopifyIdToken`
|
22
|
+
* This concern provides a method `shopify_id_token` to retrieve the Shopify Id token from either the authorization header or the URL param `id_token`.
|
23
|
+
* `ShopifyApp::JWTMiddleware` supports retrieving session token from URL param `id_token`
|
24
|
+
* `ShopifyApp::JWTMiddleware` returns early if the app is not embedded to avoid unnecessary JWT verification
|
25
|
+
* `LoginProtection` now uses `WithShopifyIdToken` concern to retrieve the Shopify Id token, thus accepting the session token from the URL param `id_token`
|
26
|
+
* Marking `ShopifyApp::JWT` to be deprecated in version 23.0.0 [1832](https://github.com/Shopify/shopify_app/pull/1832), use `ShopifyAPI::Auth::JwtPayload` instead.
|
27
|
+
* Fix infinite redirect loop caused by handling errors from Billing API [1833](https://github.com/Shopify/shopify_app/pull/1833)
|
28
|
+
|
29
|
+
22.1.0 (April 9,2024)
|
30
|
+
----------
|
31
|
+
* Extracted class - `PostAuthenticateTasks` to handle post authenticate tasks. To learn more, see [post authenticate tasks](/docs/shopify_app/authentication.md#post-authenticate-tasks). [1819](https://github.com/Shopify/shopify_app/pull/1819)
|
32
|
+
* Bumps shopify_api dependency to 14.1.0 [1826](https://github.com/Shopify/shopify_app/pull/1826)
|
33
|
+
|
4
34
|
22.0.1 (March 12, 2024)
|
5
35
|
----------
|
6
36
|
* Bumps `shopify_api` to `14.0.1` [1813](https://github.com/Shopify/shopify_app/pull/1813)
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify_app (22.0
|
4
|
+
shopify_app (22.2.0)
|
5
5
|
activeresource
|
6
6
|
addressable (~> 2.7)
|
7
7
|
jwt (>= 2.2.3)
|
8
8
|
rails (> 5.2.1)
|
9
9
|
redirect_safely (~> 1.0)
|
10
|
-
shopify_api (>= 14.0
|
10
|
+
shopify_api (>= 14.3.0, < 15.0)
|
11
11
|
sprockets-rails (>= 2.0.0)
|
12
12
|
|
13
13
|
GEM
|
@@ -104,7 +104,7 @@ GEM
|
|
104
104
|
multi_xml (>= 0.5.2)
|
105
105
|
i18n (1.13.0)
|
106
106
|
concurrent-ruby (~> 1.0)
|
107
|
-
json (2.
|
107
|
+
json (2.7.2)
|
108
108
|
jwt (2.7.0)
|
109
109
|
language_server-protocol (3.17.0.3)
|
110
110
|
loofah (2.21.3)
|
@@ -140,9 +140,10 @@ GEM
|
|
140
140
|
racc (~> 1.4)
|
141
141
|
oj (3.14.3)
|
142
142
|
openssl (3.1.0)
|
143
|
-
parallel (1.
|
144
|
-
parser (3.
|
143
|
+
parallel (1.24.0)
|
144
|
+
parser (3.3.0.5)
|
145
145
|
ast (~> 2.4.1)
|
146
|
+
racc
|
146
147
|
prettier_print (1.2.1)
|
147
148
|
pry (0.14.2)
|
148
149
|
coderay (~> 1.1)
|
@@ -192,20 +193,21 @@ GEM
|
|
192
193
|
rb-readline (0.5.5)
|
193
194
|
redirect_safely (1.0.0)
|
194
195
|
activemodel
|
195
|
-
regexp_parser (2.
|
196
|
-
rexml (3.2.
|
197
|
-
rubocop (1.
|
196
|
+
regexp_parser (2.9.0)
|
197
|
+
rexml (3.2.6)
|
198
|
+
rubocop (1.62.1)
|
198
199
|
json (~> 2.3)
|
200
|
+
language_server-protocol (>= 3.17.0)
|
199
201
|
parallel (~> 1.10)
|
200
|
-
parser (>= 3.
|
202
|
+
parser (>= 3.3.0.2)
|
201
203
|
rainbow (>= 2.2.2, < 4.0)
|
202
204
|
regexp_parser (>= 1.8, < 3.0)
|
203
205
|
rexml (>= 3.2.5, < 4.0)
|
204
|
-
rubocop-ast (>= 1.
|
206
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
205
207
|
ruby-progressbar (~> 1.7)
|
206
208
|
unicode-display_width (>= 2.4.0, < 3.0)
|
207
|
-
rubocop-ast (1.
|
208
|
-
parser (>= 3.
|
209
|
+
rubocop-ast (1.31.2)
|
210
|
+
parser (>= 3.3.0.4)
|
209
211
|
rubocop-shopify (2.13.0)
|
210
212
|
rubocop (~> 1.50)
|
211
213
|
ruby-lsp (0.5.1)
|
@@ -215,7 +217,7 @@ GEM
|
|
215
217
|
ruby-progressbar (1.13.0)
|
216
218
|
ruby2_keywords (0.0.5)
|
217
219
|
securerandom (0.2.2)
|
218
|
-
shopify_api (14.0
|
220
|
+
shopify_api (14.3.0)
|
219
221
|
activesupport
|
220
222
|
concurrent-ruby
|
221
223
|
hash_diff
|
@@ -234,16 +236,16 @@ GEM
|
|
234
236
|
actionpack (>= 5.2)
|
235
237
|
activesupport (>= 5.2)
|
236
238
|
sprockets (>= 3.0.0)
|
237
|
-
sqlite3 (1.
|
238
|
-
sqlite3 (1.
|
239
|
-
sqlite3 (1.
|
239
|
+
sqlite3 (1.7.3-arm64-darwin)
|
240
|
+
sqlite3 (1.7.3-x86_64-darwin)
|
241
|
+
sqlite3 (1.7.3-x86_64-linux)
|
240
242
|
syntax_tree (6.1.1)
|
241
243
|
prettier_print (>= 1.2.0)
|
242
244
|
thor (1.2.2)
|
243
245
|
timeout (0.3.2)
|
244
246
|
tzinfo (2.0.6)
|
245
247
|
concurrent-ruby (~> 1.0)
|
246
|
-
unicode-display_width (2.
|
248
|
+
unicode-display_width (2.5.0)
|
247
249
|
webmock (3.18.1)
|
248
250
|
addressable (>= 2.8.0)
|
249
251
|
crack (>= 0.3.2)
|
@@ -256,6 +258,7 @@ GEM
|
|
256
258
|
PLATFORMS
|
257
259
|
arm64-darwin-21
|
258
260
|
arm64-darwin-22
|
261
|
+
arm64-darwin-23
|
259
262
|
x86_64-darwin-19
|
260
263
|
x86_64-darwin-20
|
261
264
|
x86_64-darwin-21
|
data/README.md
CHANGED
@@ -129,6 +129,44 @@ These routes are configurable. See the more detailed [*Engine*](/docs/shopify_ap
|
|
129
129
|
|
130
130
|
To learn more about how this gem authenticates with Shopify, see [*Authentication*](/docs/shopify_app/authentication.md).
|
131
131
|
|
132
|
+
### New embedded app authorization strategy (Token Exchange)
|
133
|
+
|
134
|
+
> [!TIP]
|
135
|
+
> If you are building an embedded app, we **strongly** recommend using [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
136
|
+
> with [token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange) instead of the legacy authorization code grant flow.
|
137
|
+
|
138
|
+
We've introduced a new installation and authorization strategy for **embedded apps** that
|
139
|
+
eliminates the redirects that were previously necessary.
|
140
|
+
It replaces the existing [installation and authorization code grant flow](https://shopify.dev/docs/apps/auth/get-access-tokens/authorization-code-grant).
|
141
|
+
|
142
|
+
This is achieved by using [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
143
|
+
to handle automatic app installations and scope updates, while utilizing
|
144
|
+
[token exchange](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange) to retrieve an access token for
|
145
|
+
authenticated API access.
|
146
|
+
|
147
|
+
##### Enabling this new strategy in your app
|
148
|
+
|
149
|
+
1. Enable [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
150
|
+
by configuring your scopes [through the Shopify CLI](https://shopify.dev/docs/apps/tools/cli/configuration).
|
151
|
+
2. Enable the new auth strategy in your app's ShopifyApp configuration file.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
# config/initializers/shopify_app.rb
|
155
|
+
ShopifyApp.configure do |config|
|
156
|
+
#.....
|
157
|
+
config.embedded_app = true
|
158
|
+
config.new_embedded_auth_strategy = true
|
159
|
+
|
160
|
+
# If your app is configured to use online sessions, you can enable session expiry date check so a new access token
|
161
|
+
# is fetched automatically when the session expires.
|
162
|
+
# See expiry date check docs: https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/sessions.md#expiry-date
|
163
|
+
config.check_session_expiry_date = true
|
164
|
+
...
|
165
|
+
end
|
166
|
+
|
167
|
+
```
|
168
|
+
3. Enjoy a smoother and faster app installation process.
|
169
|
+
|
132
170
|
### API Versioning
|
133
171
|
|
134
172
|
[Shopify's API is versioned](https://shopify.dev/concepts/about-apis/versioning). With Shopify App `v1.11.0`, the included Shopify API gem allows developers to specify and update the Shopify API version they want their app or service to use. The Shopify API gem also surfaces warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://shopify.dev/concepts/about-apis/versioning#deprecation-practices).
|
@@ -6,14 +6,20 @@ module ShopifyApp
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
include ShopifyApp::Localization
|
9
|
-
|
9
|
+
|
10
|
+
if ShopifyApp.configuration.use_new_embedded_auth_strategy?
|
11
|
+
include ShopifyApp::TokenExchange
|
12
|
+
around_action :activate_shopify_session
|
13
|
+
else
|
14
|
+
include ShopifyApp::LoginProtection
|
15
|
+
before_action :login_again_if_different_user_or_shop
|
16
|
+
around_action :activate_shopify_session
|
17
|
+
after_action :add_top_level_redirection_headers
|
18
|
+
end
|
19
|
+
|
10
20
|
include ShopifyApp::CsrfProtection
|
11
21
|
include ShopifyApp::EmbeddedApp
|
12
22
|
include ShopifyApp::EnsureBilling
|
13
|
-
|
14
|
-
before_action :login_again_if_different_user_or_shop
|
15
|
-
around_action :activate_shopify_session
|
16
|
-
after_action :add_top_level_redirection_headers
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -16,8 +16,14 @@ module ShopifyApp
|
|
16
16
|
end
|
17
17
|
|
18
18
|
before_action :check_shop_domain
|
19
|
-
|
20
|
-
|
19
|
+
|
20
|
+
if ShopifyApp.configuration.use_new_embedded_auth_strategy?
|
21
|
+
include ShopifyApp::TokenExchange
|
22
|
+
around_action :activate_shopify_session
|
23
|
+
else
|
24
|
+
before_action :check_shop_known
|
25
|
+
before_action :validate_non_embedded_session
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
def current_shopify_domain
|
@@ -6,7 +6,11 @@ module ShopifyApp
|
|
6
6
|
include ShopifyApp::RedirectForEmbedded
|
7
7
|
|
8
8
|
included do
|
9
|
-
|
9
|
+
# Embedded auth strategy uses Shopify managed install to ensure latest access scopes,
|
10
|
+
# This will be handled automatically through token exchange
|
11
|
+
unless ShopifyApp.configuration.use_new_embedded_auth_strategy?
|
12
|
+
before_action :login_on_scope_changes
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
protected
|
@@ -23,7 +23,16 @@ module ShopifyApp
|
|
23
23
|
|
24
24
|
return respond_with_user_token_flow if start_user_token_flow?(api_session)
|
25
25
|
|
26
|
-
|
26
|
+
if ShopifyApp::VERSION < "23.0"
|
27
|
+
# deprecated in 23.0
|
28
|
+
if ShopifyApp.configuration.custom_post_authenticate_tasks.present?
|
29
|
+
ShopifyApp.configuration.post_authenticate_tasks.perform(api_session)
|
30
|
+
else
|
31
|
+
perform_post_authenticate_jobs(api_session)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
ShopifyApp.configuration.post_authenticate_tasks.perform(api_session)
|
35
|
+
end
|
27
36
|
redirect_to_app if check_billing(api_session)
|
28
37
|
end
|
29
38
|
|
@@ -7,7 +7,7 @@ module ShopifyApp
|
|
7
7
|
|
8
8
|
layout false, only: :new
|
9
9
|
|
10
|
-
after_action only: [:new, :create] do |controller|
|
10
|
+
after_action only: [:new, :create, :patch_shopify_id_token] do |controller|
|
11
11
|
controller.response.headers.except!("X-Frame-Options")
|
12
12
|
end
|
13
13
|
|
@@ -19,6 +19,10 @@ module ShopifyApp
|
|
19
19
|
authenticate
|
20
20
|
end
|
21
21
|
|
22
|
+
def patch_shopify_id_token
|
23
|
+
render(layout: "shopify_app/layouts/app_bridge")
|
24
|
+
end
|
25
|
+
|
22
26
|
def top_level_interaction
|
23
27
|
@url = login_url_with_optional_shop(top_level: true)
|
24
28
|
validate_shop_presence
|
@@ -37,6 +41,22 @@ module ShopifyApp
|
|
37
41
|
def authenticate
|
38
42
|
return render_invalid_shop_error unless sanitized_shop_name.present?
|
39
43
|
|
44
|
+
if ShopifyApp.configuration.use_new_embedded_auth_strategy?
|
45
|
+
ShopifyApp::Logger.debug("Starting OAuth - Redirecting to Shopify managed install")
|
46
|
+
start_install
|
47
|
+
else
|
48
|
+
ShopifyApp::Logger.debug("Starting OAuth - Redirecting to begin auth")
|
49
|
+
start_oauth
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_install
|
54
|
+
shop_name = sanitized_shop_name.split(".").first
|
55
|
+
install_path = "https://admin.shopify.com/store/#{shop_name}/oauth/install?client_id=#{ShopifyApp.configuration.api_key}"
|
56
|
+
redirect_to(install_path, allow_other_host: true)
|
57
|
+
end
|
58
|
+
|
59
|
+
def start_oauth
|
40
60
|
copy_return_to_param_to_session
|
41
61
|
|
42
62
|
if embedded_redirect_url?
|
@@ -44,16 +64,16 @@ module ShopifyApp
|
|
44
64
|
if embedded_param?
|
45
65
|
redirect_for_embedded
|
46
66
|
else
|
47
|
-
|
67
|
+
redirect_to_begin_oauth
|
48
68
|
end
|
49
69
|
elsif top_level?
|
50
|
-
|
70
|
+
redirect_to_begin_oauth
|
51
71
|
else
|
52
72
|
redirect_auth_to_top_level
|
53
73
|
end
|
54
74
|
end
|
55
75
|
|
56
|
-
def
|
76
|
+
def redirect_to_begin_oauth
|
57
77
|
callback_url = ShopifyApp.configuration.login_callback_url.gsub(%r{^/}, "")
|
58
78
|
ShopifyApp::Logger.debug("Starting OAuth with the following callback URL: #{callback_url}")
|
59
79
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<title><%= ShopifyApp.configuration.application_name %></title>
|
6
|
+
<%= yield :head %>
|
7
|
+
<script
|
8
|
+
data-api-key="<%= ShopifyApp.configuration.api_key %>"
|
9
|
+
src="https://cdn.shopify.com/shopifycloud/app-bridge.js">
|
10
|
+
</script>
|
11
|
+
<%= csrf_meta_tags %>
|
12
|
+
</head>
|
13
|
+
|
14
|
+
<body>
|
15
|
+
<%= yield %>
|
16
|
+
</body>
|
17
|
+
</html>
|
File without changes
|
data/config/routes.rb
CHANGED
@@ -8,6 +8,7 @@ ShopifyApp::Engine.routes.draw do
|
|
8
8
|
get login_url => :new, :as => :login
|
9
9
|
post login_url => :create, :as => :authenticate
|
10
10
|
get "logout" => :destroy, :as => :logout
|
11
|
+
get "patch_shopify_id_token" => :patch_shopify_id_token
|
11
12
|
|
12
13
|
# Kept to prevent apps relying on these routes from breaking
|
13
14
|
if login_url.gsub(%r{^/}, "") != "login"
|
data/docs/Troubleshooting.md
CHANGED
@@ -92,29 +92,6 @@ Edit `config/initializer/shopify_app.rb` and ensure the following configurations
|
|
92
92
|
+ config.shop_session_repository = 'Shop'
|
93
93
|
```
|
94
94
|
|
95
|
-
#### Inspect server logs
|
96
|
-
|
97
|
-
If you have checked the configurations above, and the app is still using cookies, then it is possible that the `shopify_app` gem defaulted to relying on cookies. This would happen when your browser allows third-party cookies and a session token was not successfully found as part of your request.
|
98
|
-
|
99
|
-
In this case, check the server logs to see if the session token was invalid:
|
100
|
-
|
101
|
-
```los
|
102
|
-
[ShopifyApp::JWT] Failed to validate JWT: [JWT::<Error>] <Failure message>
|
103
|
-
```
|
104
|
-
|
105
|
-
*Example*
|
106
|
-
|
107
|
-
```
|
108
|
-
[ShopifyApp::JWT] Failed to validate JWT: [JWT::ImmatureSignature] Signature nbf has not been reached
|
109
|
-
```
|
110
|
-
|
111
|
-
**Note:** In a local development environment, you may want to temporarily update your `Gemfile` to point to a local instance of the `shopify_app` library instad of an installed gem. This will enable you to use a debugging tool like `byebug` to debug the library.
|
112
|
-
|
113
|
-
```diff
|
114
|
-
- gem 'shopify_app', '~> 14.2'
|
115
|
-
+ gem 'shopify_app', path: '/path/to/shopify_app'
|
116
|
-
```
|
117
|
-
|
118
95
|
### My app can't make requests to the Shopify API
|
119
96
|
|
120
97
|
> **Note:** Session tokens cannot be used to make authenticated requests to the Shopify API. Learn more about authenticating your backend requests to Shopify APIs at [Shopify API authentication](https://shopify.dev/concepts/about-apis/authentication).
|
data/docs/Upgrading.md
CHANGED
@@ -8,6 +8,8 @@ This file documents important changes needed to upgrade your app's Shopify App v
|
|
8
8
|
|
9
9
|
[Unreleased](#unreleased)
|
10
10
|
|
11
|
+
[Upgrading to `v22.2.0`](#upgrading-to-v2220)
|
12
|
+
|
11
13
|
[Upgrading to `v22.0.0`](#upgrading-to-v2200)
|
12
14
|
|
13
15
|
[Upgrading to `v20.3.0`](#upgrading-to-v2030)
|
@@ -40,6 +42,29 @@ We also recommend the use of a staging site which matches your production enviro
|
|
40
42
|
|
41
43
|
If you do run into issues, we recommend looking at our [debugging tips.](https://github.com/Shopify/shopify_app/blob/main/docs/Troubleshooting.md#debugging-tips)
|
42
44
|
|
45
|
+
## Unreleased
|
46
|
+
#### (v23.0.0) - Deprecated methods in CallbackController
|
47
|
+
The following methods from `ShopifyApp::CallbackController` have been deprecated in `v23.0.0`
|
48
|
+
- `perform_after_authenticate_job`
|
49
|
+
- `install_webhooks`
|
50
|
+
- `perform_post_authenticate_jobs`
|
51
|
+
|
52
|
+
If you have overwritten these methods in your callback controller to modify the behavior of the inherited `CallbackController`, you will need to
|
53
|
+
update your app to use configurable option `config.custom_post_authenticate_tasks` instead. See [post authenticate tasks](/docs/shopify_app/authentication.md#post-authenticate-tasks)
|
54
|
+
for more information.
|
55
|
+
|
56
|
+
#### (v23.0.0) - Deprecated "ShopifyApp::JWT" class
|
57
|
+
The `ShopifyApp::JWT` class has been deprecated in `v23.0.0`. Use [ShopifyAPI::Auth::JwtPayload](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/auth/jwt_payload.rb)
|
58
|
+
class from the `shopify_api` gem instead. A search and replace should be enough for this migration.
|
59
|
+
- `ShopifyAPI::Auth::JwtPayload` is a superset of the `ShopifyApp::JWT` class, and contains methods that were available in `ShopifyApp::JWT`.
|
60
|
+
- `ShopifyAPI::Auth::JwtPayload` raises `ShopifyAPI::Errors::InvalidJwtTokenError` if the token is invalid.
|
61
|
+
|
62
|
+
## Upgrading to `v22.2.0`
|
63
|
+
#### Added new feature for zero redirect embedded app authorization flow - Token Exchange
|
64
|
+
A new embedded app authorization strategy has been introduced in `v22.2.0` that eliminates the redirects that were previously necessary for OAuth.
|
65
|
+
It can replace the existing installation and authorization code grant flow.
|
66
|
+
See [new embedded app authorization strategy](./README.md#new-embedded-app-authorization-strategy) for more information.
|
67
|
+
|
43
68
|
## Upgrading to `v22.0.0`
|
44
69
|
#### Dropped support for Ruby 2.x
|
45
70
|
Support for Ruby 2.x has been dropped as it is no longer supported. You'll need to upgrade to 3.x.x
|
@@ -10,31 +10,83 @@ See [*Getting started with session token authentication*](https://shopify.dev/do
|
|
10
10
|
|
11
11
|
#### Table of contents
|
12
12
|
|
13
|
-
* [OAuth
|
14
|
-
* [
|
15
|
-
* [
|
13
|
+
* [Supported types of OAuth Flow](#supported-types-of-oauth)
|
14
|
+
* [Token Exchange](#token-exchange)
|
15
|
+
* [Authorization Code Grant Flow](#authorization-code-grant-flow)
|
16
|
+
* [OAuth callback](#oauth-callback)
|
17
|
+
* [Customizing callback controller](#customizing-callback-controller)
|
18
|
+
* [Detecting scope changes](#detecting-scope-changes-1)
|
19
|
+
* [Run jobs after the OAuth flow](#post-authenticate-tasks)
|
16
20
|
* [Rotate API credentials](#rotate-api-credentials)
|
17
21
|
* [Making authenticated API requests after authorization](#making-authenticated-api-requests-after-authorization)
|
18
22
|
|
19
|
-
## OAuth
|
23
|
+
## Supported types of OAuth
|
24
|
+
> [!TIP]
|
25
|
+
> If you are building an embedded app, we **strongly** recommend using [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
26
|
+
with [token exchange](#token-exchange) instead of the authorization code grant flow.
|
20
27
|
|
21
|
-
|
28
|
+
1. [Token Exchange](#token-exchange)
|
29
|
+
- Recommended and is only available for embedded apps
|
30
|
+
- Doesn't require redirects, which makes authorization faster and prevents flickering when loading the app
|
31
|
+
- Access scope changes are handled by Shopify when you use [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
32
|
+
2. [Authorization Code Grant Flow](#authorization-code-grant-flow)
|
33
|
+
- Suitable for non-embedded apps
|
34
|
+
- Installations, and access scope changes are managed by the app
|
22
35
|
|
23
|
-
|
36
|
+
## Token Exchange
|
37
|
+
|
38
|
+
OAuth process by exchanging the current user's [session token (shopify id token)](https://shopify.dev/docs/apps/auth/session-tokens) for an
|
39
|
+
[access token](https://shopify.dev/docs/apps/auth/access-token-types/online.md) to make
|
40
|
+
authenticated Shopify API queries. This will replace authorization code grant flow completely when your app is configured with [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).
|
41
|
+
|
42
|
+
To enable token exchange authorization strategy, you can follow the steps in ["New embedded app authorization strategy"](/README.md#new-embedded-app-authorization-strategy).
|
43
|
+
Upon completion of the token exchange to get the access token, [post authenticated tasks](#post-authenticate-tasks) will be run.
|
44
|
+
|
45
|
+
Learn more about:
|
46
|
+
- [How token exchange works](https://shopify.dev/docs/apps/auth/get-access-tokens/token-exchange)
|
47
|
+
- [Using Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation)
|
48
|
+
- [Configuring access scopes through the Shopify CLI](https://shopify.dev/docs/apps/tools/cli/configuration)
|
49
|
+
|
50
|
+
#### Handling invalid access tokens
|
51
|
+
If the access token used to make an API call is invalid, the token exchange strategy will handle the error and try to retrieve a new access token before retrying
|
52
|
+
the same operation.
|
53
|
+
See ["Re-fetching an access token when API returns Unauthorized"](/docs/shopify_app/sessions.md#re-fetching-an-access-token-when-api-returns-unauthorized) section for more information.
|
54
|
+
|
55
|
+
#### Detecting scope changes
|
56
|
+
|
57
|
+
##### Shopify managed installation
|
58
|
+
If your access scopes are [configured through the Shopify CLI](https://shopify.dev/docs/apps/tools/cli/configuration), scope changes will be handled by Shopify automatically.
|
59
|
+
Learn more about [Shopify managed installation](https://shopify.dev/docs/apps/auth/installation#shopify-managed-installation).
|
60
|
+
Using token exchange will ensure that the access token retrieved will always have the latest access scopes granted by the user.
|
61
|
+
|
62
|
+
## Authorization Code Grant Flow
|
63
|
+
Authorization code grant flow is the OAuth flow that requires the app to redirect the user
|
64
|
+
to Shopify for installation/authorization of the app to access the shop's data. It is still required for apps that are not embedded.
|
65
|
+
|
66
|
+
To perform [authorization code grant flow](https://shopify.dev/docs/apps/auth/get-access-tokens/authorization-code-grant), you app will need to handle
|
67
|
+
[begin OAuth](#begin-oauth) and [OAuth callback](#oauth-callback) routes.
|
68
|
+
|
69
|
+
### Begin OAuth
|
70
|
+
ShopifyApp automatically redirects the user to Shopify to complete OAuth to install the app when the `ShopifyApp.configuration.login_url` is reached.
|
71
|
+
Behind the scenes the ShopifyApp gem starts the process by calling `ShopifyAPI::Auth::Oauth.begin_auth` to build the
|
72
|
+
redirect URL with necessary parameters like the OAuth callback URL, scopes requested, type of access token (offline or online) requested, etc.
|
73
|
+
The ShopifyApp gem then redirect the merchant to Shopify, to ask for permission to install the app. (See [ShopifyApp::SessionsController.redirect_to_begin_oauth](https://github.com/Shopify/shopify_app/blob/main/app/controllers/shopify_app/sessions_controller.rb#L76-L96)
|
74
|
+
for detailed implementation)
|
75
|
+
|
76
|
+
### OAuth callback
|
77
|
+
|
78
|
+
Shopify will redirect the merchant back to your app's callback URL once they approve the app installation.
|
79
|
+
Upon completing the OAuth flow, Shopify calls the app at `ShopifyApp.configuration.login_callback_url`. (This was provided to Shopify in the OAuth begin URL parameters)
|
24
80
|
|
25
81
|
The default callback controller [`ShopifyApp::CallbackController`](../../app/controllers/shopify_app/callback_controller.rb) provides the following behaviour:
|
26
82
|
|
27
83
|
1. Logging into the shop and resetting the session
|
28
84
|
2. Storing the session to the `SessionRepository`
|
29
|
-
3. [
|
30
|
-
4.
|
31
|
-
5. [Run jobs after the OAuth flow](#run-jobs-after-the-oauth-flow)
|
32
|
-
6. Redirecting to the return address
|
33
|
-
|
85
|
+
3. [Post authenticate tasks](#post-authenticate-tasks)
|
86
|
+
4. Redirecting to the return address
|
34
87
|
|
35
88
|
#### Customizing callback controller
|
36
|
-
If
|
37
|
-
Inheriting from `ShopifyApp::CallbackController` and hook into or override any of the defined helper methods.
|
89
|
+
If you need to define a custom callback controller to handle your app's use case, you can configure the callback route to your controller.
|
38
90
|
|
39
91
|
Example:
|
40
92
|
|
@@ -42,11 +94,9 @@ Example:
|
|
42
94
|
```ruby
|
43
95
|
# web/app/controllers/my_custom_callback_controller.rb
|
44
96
|
|
45
|
-
class MyCustomCallbackController
|
46
|
-
|
47
|
-
|
48
|
-
def install_webhooks(session)
|
49
|
-
# My custom override/definition to install webhooks
|
97
|
+
class MyCustomCallbackController
|
98
|
+
def callback
|
99
|
+
# My custom callback logic
|
50
100
|
end
|
51
101
|
end
|
52
102
|
```
|
@@ -69,11 +119,46 @@ Rails.application.routes.draw do
|
|
69
119
|
end
|
70
120
|
```
|
71
121
|
|
72
|
-
###
|
122
|
+
### Detecting scope changes
|
123
|
+
When the OAuth process is completed, the created session has a `scope` field which holds all of the access scopes that were requested from the merchant at the time.
|
124
|
+
|
125
|
+
When an app's access scopes change, it needs to request merchants to go through OAuth again to renew its permissions.
|
126
|
+
|
127
|
+
See [Handling changes in access scopes](/docs/shopify_app/handling-access-scopes-changes.md).
|
128
|
+
|
129
|
+
## Post Authenticate tasks
|
130
|
+
After authentication is complete, a few tasks are run by default by PostAuthenticateTasks:
|
131
|
+
1. [Installing Webhooks](/docs/shopify_app/webhooks.md)
|
132
|
+
2. [Run configured after_authenticate_job](#after_authenticate_job)
|
133
|
+
|
134
|
+
The [PostAuthenticateTasks](https://github.com/Shopify/shopify_app/blob/main/lib/shopify_app/auth/post_authenticate_tasks.rb)
|
135
|
+
class is responsible for triggering the webhooks manager for webhooks registration, and enqueue jobs from [after_authenticate_job](#after_authenticate_job).
|
136
|
+
|
137
|
+
If you simply need to enqueue more jobs to run after authenticate, use [after_authenticate_job](#after_authenticate_job) to define these jobs.
|
138
|
+
|
139
|
+
If your post authentication tasks is more complex and is different than just installing webhooks and enqueuing jobs,
|
140
|
+
you can customize the post authenticate tasks by creating a new class that has a `self.perform(session)` method,
|
141
|
+
and configuring `custom_post_authenticate_tasks` in the initializer.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
# my_custom_post_authenticate_task.rb
|
145
|
+
class MyCustomPostAuthenticateTask
|
146
|
+
def self.perform(session)
|
147
|
+
# This will be triggered after OAuth callback and token exchange completion
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# config/initializers/shopify_app.rb
|
152
|
+
ShopifyApp.configure do |config|
|
153
|
+
config.custom_post_authenticate_tasks = "MyCustomPostAuthenticateTask"
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
#### after_authenticate_job
|
73
158
|
|
74
159
|
See [`ShopifyApp::AfterAuthenticateJob`](/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb).
|
75
160
|
|
76
|
-
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
|
161
|
+
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. To configure the after authenticate job, update your initializer as follows:
|
77
162
|
|
78
163
|
```ruby
|
79
164
|
ShopifyApp.configure do |config|
|