shopify_app 21.9.0 → 21.10.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/release.yml +1 -1
- data/CHANGELOG.md +6 -1
- data/Gemfile.lock +1 -1
- data/docs/shopify_app/sessions.md +26 -17
- data/lib/generators/shopify_app/user_model/templates/db/migrate/add_user_expires_at_column.erb +5 -0
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +20 -0
- data/lib/shopify_app/configuration.rb +8 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +6 -0
- data/lib/shopify_app/session/session_repository.rb +12 -5
- data/lib/shopify_app/session/shop_session_storage.rb +4 -0
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +4 -0
- data/lib/shopify_app/session/user_session_storage.rb +4 -0
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +25 -0
- data/lib/shopify_app/version.rb +1 -1
- data/package.json +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 927f0886c6d7be713738a4c38d2a1c5319593d2d8e4d200d854957abae73ac09
|
4
|
+
data.tar.gz: cca13c50d4cc99853ef10e119d4cb10cf96ba786ee9e146c2acacc12758d741f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db9c6d4fdee1744d974fcde46f54d4246c2886dafb4d31f3423d9c903566f730c06a0b3187a21cdd534d7ee63be95c1fa318e85c007b53f682cbf7a6d3184df2
|
7
|
+
data.tar.gz: eb437382bf4fba13da3d3780fd05e29360807c8d999239d129dd4ff5e92fc63de33dea382deb9ab9f0e9552d208a1405acb5aa68cb85c20a7310afd81681bcb0
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
Unreleased
|
2
2
|
----------
|
3
3
|
|
4
|
-
21.
|
4
|
+
21.10.0 (January 24, 2024)
|
5
|
+
----------
|
6
|
+
* Fix session deletion for users with customized session storage[#1773](https://github.com/Shopify/shopify_app/pull/1773)
|
7
|
+
* Add configuration flag `check_session_expiry_date` to trigger a re-auth when the (user) session is expired. The session expiry date must be stored and retrieved for this flag to be effective. When the `UserSessionStorageWithScopes` concern is used, a DB migration can be generated with `rails generate shopify_app:user_model --skip` and should be applied before enabling that flag[#1757](https://github.com/Shopify/shopify_app/pull/1757)
|
8
|
+
|
9
|
+
21.9.0 (January 16, 2024)
|
5
10
|
----------
|
6
11
|
* Fix `add_webhook` generator to create the webhook jobs under the correct directory[#1748](https://github.com/Shopify/shopify_app/pull/1748)
|
7
12
|
* Add support for metafield_namespaces in webhook registration [#1745](https://github.com/Shopify/shopify_app/pull/1745)
|
data/Gemfile.lock
CHANGED
@@ -4,23 +4,27 @@ Sessions are used to make contextual API calls for either a shop (offline sessio
|
|
4
4
|
|
5
5
|
#### Table of contents
|
6
6
|
|
7
|
-
- [Sessions](#sessions
|
8
|
-
|
9
|
-
- [
|
10
|
-
- [
|
11
|
-
- [
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
- [Sessions](#sessions)
|
8
|
+
- [Table of contents](#table-of-contents)
|
9
|
+
- [Sessions](#sessions-1)
|
10
|
+
- [Types of session tokens](#types-of-session-tokens)
|
11
|
+
- [Session token storage](#session-token-storage)
|
12
|
+
- [Shop (offline) token storage](#shop-offline-token-storage)
|
13
|
+
- [User (online) token storage](#user-online-token-storage)
|
14
|
+
- [In-memory Session Storage for testing](#in-memory-session-storage-for-testing)
|
15
|
+
- [Customizing Session Storage with `ShopifyApp::SessionRepository`](#customizing-session-storage-with-shopifyappsessionrepository)
|
16
|
+
- [⚠️ Custom Session Storage Requirements](#️--custom-session-storage-requirements)
|
17
|
+
- [Available `ActiveSupport::Concerns` that contains implementation of the above methods](#available-activesupportconcerns-that-contains-implementation-of-the-above-methods)
|
18
|
+
- [Loading Sessions](#loading-sessions)
|
15
19
|
- [Getting Sessions with Controller Concerns](#getting-sessions-with-controller-concerns)
|
16
|
-
- [Shop
|
17
|
-
- [User
|
18
|
-
- [Getting
|
19
|
-
- [Access scopes](#access-scopes)
|
20
|
-
|
21
|
-
|
22
|
-
- [Migrating from shop-based to user-based token strategy](#migrating-from-shop-based-to-user-based-token-strategy)
|
23
|
-
- [Migrating from ShopifyApi::Auth::SessionStorage to ShopifyApp::SessionStorage](#migrating-from-shopifyapiauthsessionstorage-to-shopifyappsessionstorage)
|
20
|
+
- [**Shop Sessions - `EnsureInstalled`**](#shop-sessions---ensureinstalled)
|
21
|
+
- [User Sessions - `EnsureHasSession`](#user-sessions---ensurehassession)
|
22
|
+
- [Getting sessions from a Shop or User model record - 'with\_shopify\_session'](#getting-sessions-from-a-shop-or-user-model-record---with_shopify_session)
|
23
|
+
- [Access scopes](#access-scopes)
|
24
|
+
- [`ShopifyApp::ShopSessionStorageWithScopes`](#shopifyappshopsessionstoragewithscopes)
|
25
|
+
- [`ShopifyApp::UserSessionStorageWithScopes`](#shopifyappusersessionstoragewithscopes)
|
26
|
+
- [Migrating from shop-based to user-based token strategy](#migrating-from-shop-based-to-user-based-token-strategy)
|
27
|
+
- [Migrating from `ShopifyApi::Auth::SessionStorage` to `ShopifyApp::SessionStorage`](#migrating-from-shopifyapiauthsessionstorage-to-shopifyappsessionstorage)
|
24
28
|
|
25
29
|
## Sessions
|
26
30
|
#### Types of session tokens
|
@@ -103,6 +107,7 @@ The custom **Shop** repository must implement the following methods:
|
|
103
107
|
| `self.store(auth_session)` | `auth_session` (ShopifyAPI::Auth::Session) | - |
|
104
108
|
| `self.retrieve(id)` | `id` (String) | ShopifyAPI::Auth::Session |
|
105
109
|
| `self.retrieve_by_shopify_domain(shopify_domain)` | `shopify_domain` (String) | ShopifyAPI::Auth::Session |
|
110
|
+
| `self.destroy_by_shopify_domain(shopify_domain)` | `shopify_domain` (String) | - |
|
106
111
|
|
107
112
|
The custom **User** repository must implement the following methods:
|
108
113
|
| Method | Parameters | Return Type |
|
@@ -110,6 +115,7 @@ The custom **User** repository must implement the following methods:
|
|
110
115
|
| `self.store(auth_session, user)` | <li>`auth_session` (ShopifyAPI::Auth::Session)<br><li>`user` (ShopifyAPI::Auth::AssociatedUser) | - |
|
111
116
|
| `self.retrieve(id)` | `id` (String) | `ShopifyAPI::Auth::Session` |
|
112
117
|
| `self.retrieve_by_shopify_user_id(user_id)` | `user_id` (String) | `ShopifyAPI::Auth::Session` |
|
118
|
+
| `self.destroy_by_shopify_user_id(user_id)` | `user_id` (String) | - |
|
113
119
|
|
114
120
|
|
115
121
|
These methods are already implemented as a part of the `User` and `Shop` models generated from this gem's generator.
|
@@ -153,7 +159,7 @@ end
|
|
153
159
|
```
|
154
160
|
|
155
161
|
##### User Sessions - `EnsureHasSession`
|
156
|
-
- [EnsureHasSession](https://github.com/Shopify/shopify_app/blob/main/app/controllers/concerns/shopify_app/ensure_has_session.rb) controller concern will load a user session via `current_shopify_session`. As part of loading this session, this concern will also ensure that the user session has the appropriate scopes needed for the application. If the user isn't found or has fewer permitted scopes than are required, they will be prompted to authorize the application.
|
162
|
+
- [EnsureHasSession](https://github.com/Shopify/shopify_app/blob/main/app/controllers/concerns/shopify_app/ensure_has_session.rb) controller concern will load a user session via `current_shopify_session`. As part of loading this session, this concern will also ensure that the user session has the appropriate scopes needed for the application and that it is not expired (when `check_session_expiry_date` is enabled). If the user isn't found or has fewer permitted scopes than are required, they will be prompted to authorize the application.
|
157
163
|
- This controller concern should be used if you don't need your app to make calls on behalf of a user. With that in mind, there are a few other embedded concerns that are mixed in to ensure that embedding, CSRF, localization, and billing allow the action for the user.
|
158
164
|
- Example
|
159
165
|
```ruby
|
@@ -228,6 +234,9 @@ class User < ActiveRecord::Base
|
|
228
234
|
end
|
229
235
|
```
|
230
236
|
|
237
|
+
## Expiry date
|
238
|
+
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.
|
239
|
+
|
231
240
|
## Migrating from shop-based to user-based token strategy
|
232
241
|
|
233
242
|
1. Run the `user_model` generator as [mentioned above](#user-online-token-storage).
|
@@ -40,6 +40,26 @@ module ShopifyApp
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def create_expires_at_storage_in_user_model
|
44
|
+
expires_at_column_prompt = <<~PROMPT
|
45
|
+
It is highly recommended that apps record the User session expiry date. \
|
46
|
+
This will allow to check if the session has expired and re-authenticate \
|
47
|
+
without a first call to Shopify.
|
48
|
+
|
49
|
+
After running the migration, the `check_session_expiry_date` configuration can be enabled.
|
50
|
+
|
51
|
+
The following migration will add an `expires_at` column to the User model. \
|
52
|
+
Do you want to include this migration? [y/n]
|
53
|
+
PROMPT
|
54
|
+
|
55
|
+
if new_shopify_cli_app? || Rails.env.test? || yes?(expires_at_column_prompt)
|
56
|
+
migration_template(
|
57
|
+
"db/migrate/add_user_expires_at_column.erb",
|
58
|
+
"db/migrate/add_user_expires_at_column.rb",
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
43
63
|
def update_shopify_app_initializer
|
44
64
|
gsub_file("config/initializers/shopify_app.rb", "ShopifyApp::InMemoryUserSessionStore", "User")
|
45
65
|
end
|
@@ -20,6 +20,7 @@ module ShopifyApp
|
|
20
20
|
attr_accessor :api_version
|
21
21
|
|
22
22
|
attr_accessor :reauth_on_access_scope_changes
|
23
|
+
attr_accessor :check_session_expiry_date
|
23
24
|
attr_accessor :log_level
|
24
25
|
|
25
26
|
# customise urls
|
@@ -44,6 +45,9 @@ module ShopifyApp
|
|
44
45
|
# takes a ShopifyApp::BillingConfiguration object
|
45
46
|
attr_accessor :billing
|
46
47
|
|
48
|
+
# Work in Progress: enables token exchange authentication flow
|
49
|
+
attr_accessor :wip_new_embedded_auth_strategy
|
50
|
+
|
47
51
|
def initialize
|
48
52
|
@root_url = "/"
|
49
53
|
@myshopify_domain = "myshopify.com"
|
@@ -118,6 +122,10 @@ module ShopifyApp
|
|
118
122
|
def user_access_scopes
|
119
123
|
@user_access_scopes || scope
|
120
124
|
end
|
125
|
+
|
126
|
+
def use_new_embedded_auth_strategy?
|
127
|
+
wip_new_embedded_auth_strategy && embedded_app?
|
128
|
+
end
|
121
129
|
end
|
122
130
|
|
123
131
|
class BillingConfiguration
|
@@ -30,6 +30,12 @@ module ShopifyApp
|
|
30
30
|
return redirect_to_login
|
31
31
|
end
|
32
32
|
|
33
|
+
if ShopifyApp.configuration.check_session_expiry_date && current_shopify_session.expired?
|
34
|
+
ShopifyApp::Logger.debug("Session expired, redirecting to login")
|
35
|
+
clear_shopify_session
|
36
|
+
return redirect_to_login
|
37
|
+
end
|
38
|
+
|
33
39
|
if ShopifyApp.configuration.reauth_on_access_scope_changes &&
|
34
40
|
!ShopifyApp.configuration.user_access_scopes_strategy.covers_scopes?(current_shopify_session)
|
35
41
|
clear_shopify_session
|
@@ -23,6 +23,14 @@ module ShopifyApp
|
|
23
23
|
user_storage.retrieve_by_shopify_user_id(user_id)
|
24
24
|
end
|
25
25
|
|
26
|
+
def destroy_shop_session_by_domain(shopify_domain)
|
27
|
+
shop_storage.destroy_by_shopify_domain(shopify_domain)
|
28
|
+
end
|
29
|
+
|
30
|
+
def destroy_user_session_by_shopify_user_id(user_id)
|
31
|
+
user_storage.destroy_by_shopify_user_id(user_id)
|
32
|
+
end
|
33
|
+
|
26
34
|
def store_shop_session(session)
|
27
35
|
shop_storage.store(session)
|
28
36
|
end
|
@@ -73,18 +81,17 @@ module ShopifyApp
|
|
73
81
|
def delete_session(id)
|
74
82
|
match = id.match(/^offline_(.*)/)
|
75
83
|
|
76
|
-
|
84
|
+
if match
|
77
85
|
domain = match[1]
|
78
86
|
ShopifyApp::Logger.debug("Destroying session by domain - domain: #{domain}")
|
79
|
-
|
87
|
+
destroy_shop_session_by_domain(domain)
|
88
|
+
|
80
89
|
else
|
81
90
|
shopify_user_id = id.split("_").last
|
82
91
|
ShopifyApp::Logger.debug("Destroying session by user - user_id: #{shopify_user_id}")
|
83
|
-
|
92
|
+
destroy_user_session_by_shopify_user_id(shopify_user_id)
|
84
93
|
end
|
85
94
|
|
86
|
-
record.destroy
|
87
|
-
|
88
95
|
true
|
89
96
|
end
|
90
97
|
|
@@ -15,6 +15,7 @@ module ShopifyApp
|
|
15
15
|
user.shopify_token = auth_session.access_token
|
16
16
|
user.shopify_domain = auth_session.shop
|
17
17
|
user.access_scopes = auth_session.scope.to_s
|
18
|
+
user.expires_at = auth_session.expires
|
18
19
|
|
19
20
|
user.save!
|
20
21
|
user.id
|
@@ -30,6 +31,10 @@ module ShopifyApp
|
|
30
31
|
construct_session(user)
|
31
32
|
end
|
32
33
|
|
34
|
+
def destroy_by_shopify_user_id(user_id)
|
35
|
+
destroy_by(shopify_user_id: user_id)
|
36
|
+
end
|
37
|
+
|
33
38
|
private
|
34
39
|
|
35
40
|
def construct_session(user)
|
@@ -52,6 +57,7 @@ module ShopifyApp
|
|
52
57
|
scope: user.access_scopes,
|
53
58
|
associated_user_scope: user.access_scopes,
|
54
59
|
associated_user: associated_user,
|
60
|
+
expires: user.expires_at,
|
55
61
|
)
|
56
62
|
end
|
57
63
|
end
|
@@ -67,5 +73,24 @@ module ShopifyApp
|
|
67
73
|
rescue NotImplementedError, NoMethodError
|
68
74
|
raise NotImplementedError, "#access_scopes= must be defined to hook into stored access scopes"
|
69
75
|
end
|
76
|
+
|
77
|
+
def expires_at=(expires_at)
|
78
|
+
super
|
79
|
+
rescue NotImplementedError, NoMethodError
|
80
|
+
if ShopifyApp.configuration.check_session_expiry_date
|
81
|
+
raise NotImplementedError,
|
82
|
+
"#expires_at= must be defined to handle storing the session expiry date"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def expires_at
|
87
|
+
super
|
88
|
+
rescue NotImplementedError, NoMethodError
|
89
|
+
if ShopifyApp.configuration.check_session_expiry_date
|
90
|
+
raise NotImplementedError, "#expires_at must be defined to check the session expiry date"
|
91
|
+
end
|
92
|
+
|
93
|
+
nil
|
94
|
+
end
|
70
95
|
end
|
71
96
|
end
|
data/lib/shopify_app/version.rb
CHANGED
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify_app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 21.
|
4
|
+
version: 21.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activeresource
|
@@ -416,6 +416,7 @@ files:
|
|
416
416
|
- lib/generators/shopify_app/shop_model/templates/shops.yml
|
417
417
|
- lib/generators/shopify_app/shopify_app_generator.rb
|
418
418
|
- lib/generators/shopify_app/user_model/templates/db/migrate/add_user_access_scopes_column.erb
|
419
|
+
- lib/generators/shopify_app/user_model/templates/db/migrate/add_user_expires_at_column.erb
|
419
420
|
- lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb
|
420
421
|
- lib/generators/shopify_app/user_model/templates/user.rb
|
421
422
|
- lib/generators/shopify_app/user_model/templates/users.yml
|