shopify_app 22.5.2 → 23.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yaml +6 -0
- data/.github/workflows/build.yml +5 -5
- data/.github/workflows/close-waiting-for-response-issues.yml +1 -1
- data/.github/workflows/release.yml +2 -2
- data/.github/workflows/remove-labels-on-activity.yml +2 -3
- data/.github/workflows/rubocop.yml +2 -2
- data/CHANGELOG.md +22 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +181 -122
- data/README.md +105 -25
- data/Rakefile +13 -0
- data/app/controllers/shopify_app/callback_controller.rb +2 -40
- data/app/controllers/shopify_app/extension_verification_controller.rb +1 -1
- data/app/jobs/shopify_app/script_tags_manager_job.rb +16 -0
- data/docs/Releasing.md +113 -19
- data/docs/Upgrading.md +72 -0
- data/docs/shopify_app/content-security-policy.md +50 -3
- data/docs/shopify_app/controller-concerns.md +20 -0
- data/docs/shopify_app/script-tags.md +52 -0
- data/docs/shopify_app/sessions.md +149 -22
- data/lib/generators/shopify_app/add_app_uninstalled_job/templates/app_uninstalled_job.rb.tt +2 -2
- data/lib/generators/shopify_app/add_privacy_jobs/templates/customers_data_request_job.rb.tt +2 -2
- data/lib/generators/shopify_app/add_privacy_jobs/templates/customers_redact_job.rb.tt +2 -2
- data/lib/generators/shopify_app/add_privacy_jobs/templates/shop_redact_job.rb.tt +2 -2
- data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb.tt +2 -2
- data/lib/generators/shopify_app/install/install_generator.rb +1 -1
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +18 -0
- data/lib/generators/shopify_app/shop_model/templates/db/migrate/add_shop_access_token_expiry_columns.erb +7 -0
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +1 -1
- data/lib/generators/shopify_app/user_model/templates/user.rb +1 -1
- data/lib/shopify_app/auth/post_authenticate_tasks.rb +8 -0
- data/lib/shopify_app/auth/token_exchange.rb +7 -0
- data/lib/shopify_app/configuration.rb +5 -5
- data/lib/shopify_app/controller_concerns/login_protection.rb +12 -8
- data/lib/shopify_app/engine.rb +2 -5
- data/lib/shopify_app/errors.rb +2 -0
- data/lib/shopify_app/managers/script_tags_manager.rb +348 -0
- data/lib/shopify_app/session/shop_session_storage.rb +84 -2
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +6 -0
- data/lib/shopify_app/session/user_session_storage.rb +21 -2
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +6 -0
- data/lib/shopify_app/utils.rb +1 -1
- data/lib/shopify_app/version.rb +1 -1
- data/lib/shopify_app.rb +12 -7
- data/package.json +1 -1
- data/shopify_app.gemspec +9 -10
- data/translation.yml +1 -0
- data/yarn.lock +7 -9
- metadata +63 -46
- data/lib/shopify_app/middleware/jwt_middleware.rb +0 -48
- data/lib/shopify_app/session/jwt.rb +0 -73
- /data/{lib/shopify_app/jobs → app/jobs/shopify_app}/webhooks_manager_job.rb +0 -0
data/README.md
CHANGED
|
@@ -31,6 +31,12 @@ This gem requires that you have the following credentials:
|
|
|
31
31
|
|
|
32
32
|
## Usage
|
|
33
33
|
|
|
34
|
+
> [!NOTE]
|
|
35
|
+
> This package works best with the Shopify CLI. Learn more at https://shopify.dev/docs/apps/build/cli-for-apps
|
|
36
|
+
>
|
|
37
|
+
> To get started with a Rails app already connected to the Shopify CLI, run `shopify app init --template=ruby` for a complete setup app. (Recommended)
|
|
38
|
+
> Follow the instructions below to use this gem with a new or existing Rails app.
|
|
39
|
+
|
|
34
40
|
1. To get started, create a new Rails app:
|
|
35
41
|
|
|
36
42
|
``` sh
|
|
@@ -43,44 +49,120 @@ rails new my_shopify_app
|
|
|
43
49
|
bundle add shopify_app
|
|
44
50
|
```
|
|
45
51
|
|
|
46
|
-
3.
|
|
47
|
-
There are a variety of way of doing this, but for a development environment we recommended the [`dotenv-rails`](https://github.com/bkeepers/dotenv) gem.
|
|
48
|
-
Create a `.env` file in the root of your Rails app to specify the full host and Shopify API credentials:
|
|
52
|
+
3. Connect the Shopify CLI to your app:
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
### Setting up Shopify CLI
|
|
55
|
+
|
|
56
|
+
For a more detailed guide on how to set up Shopify CLI, see the [Shopify CLI documentation](https://shopify.dev/docs/apps/build/cli-for-apps/app-structure).
|
|
57
|
+
|
|
58
|
+
To use your Rails app with Shopify CLI, you'll need to create the required configuration files and set up your project structure:
|
|
59
|
+
|
|
60
|
+
1. Create a `package.json` file in your app's root directory:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"name": "my-shopify-app",
|
|
65
|
+
"version": "1.0.0",
|
|
66
|
+
"description": "Shopify app built with Rails",
|
|
67
|
+
"scripts": {},
|
|
68
|
+
"dependencies": {},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=18.0.0"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
54
73
|
```
|
|
74
|
+
This is required for the Shopify CLI to work. It will be used if you add extension like Checkout UI [extensions](https://shopify.dev/docs/api/checkout-extensions) to your app.
|
|
55
75
|
|
|
56
|
-
|
|
76
|
+
2. Create a `shopify.app.toml` configuration file in your app's root:
|
|
57
77
|
|
|
58
|
-
```
|
|
59
|
-
|
|
78
|
+
```toml
|
|
79
|
+
# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration
|
|
80
|
+
|
|
81
|
+
client_id = ""
|
|
82
|
+
name = "My Shopify App"
|
|
83
|
+
handle = "my-shopify-app"
|
|
84
|
+
application_url = "https://localhost:3000"
|
|
85
|
+
embedded = true
|
|
86
|
+
|
|
87
|
+
[access_scopes]
|
|
88
|
+
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
|
|
89
|
+
scopes = "write_products"
|
|
90
|
+
|
|
91
|
+
[auth]
|
|
92
|
+
redirect_urls = [
|
|
93
|
+
"https://localhost:3000/api/auth",
|
|
94
|
+
"https://localhost:3000/api/auth/callback",
|
|
95
|
+
"https://localhost:3000/auth/callback",
|
|
96
|
+
"https://localhost:3000/auth/shopify/callback"
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
[webhooks]
|
|
100
|
+
api_version = "2024-10"
|
|
101
|
+
|
|
102
|
+
[[webhooks.subscriptions]]
|
|
103
|
+
topics = ["app/uninstalled"]
|
|
104
|
+
uri = "/api/webhooks"
|
|
105
|
+
|
|
106
|
+
[pos]
|
|
107
|
+
embedded = false
|
|
108
|
+
|
|
109
|
+
[build]
|
|
110
|
+
automatically_update_urls_on_dev = true
|
|
111
|
+
dev_store_url = "YOUR-DEV-STORE.myshopify.com"
|
|
60
112
|
```
|
|
61
113
|
|
|
62
|
-
|
|
114
|
+
3. Create a `shopify.web.toml` file to configure how Shopify CLI runs your Rails app:
|
|
63
115
|
|
|
64
|
-
```
|
|
65
|
-
|
|
116
|
+
```toml
|
|
117
|
+
# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration
|
|
118
|
+
|
|
119
|
+
[commands]
|
|
120
|
+
dev = "bin/rails server -b 0.0.0.0 -e development"
|
|
121
|
+
build = "RAILS_ENV=production bin/rails assets:precompile"
|
|
66
122
|
```
|
|
67
123
|
|
|
68
|
-
|
|
124
|
+
4. (Optional) Update your Rails development configuration to allow Shopify's tunnel hosts. In `config/environments/development.rb`, add:
|
|
69
125
|
|
|
70
|
-
```
|
|
71
|
-
|
|
126
|
+
```ruby
|
|
127
|
+
Rails.application.configure do
|
|
128
|
+
# Allow ngrok tunnels for secure Shopify OAuth redirects
|
|
129
|
+
config.hosts = (config.hosts rescue []) << /[-\w]+\.ngrok\.io/
|
|
130
|
+
# Allow Cloudflare tunnels for secure Shopify OAuth redirects
|
|
131
|
+
config.hosts = (config.hosts rescue []) << /[-\w]+\.trycloudflare\.com/
|
|
132
|
+
|
|
133
|
+
# Or to allow all hosts in development (less secure):
|
|
134
|
+
# config.hosts.clear
|
|
135
|
+
|
|
136
|
+
# ... rest of your configuration
|
|
137
|
+
end
|
|
72
138
|
```
|
|
139
|
+
With the Shopify CLI you can use [localhost development](https://shopify.dev/docs/apps/build/cli-for-apps/development) to run your app.
|
|
73
140
|
|
|
74
|
-
|
|
141
|
+
5. Generate your API credentials
|
|
142
|
+
```
|
|
143
|
+
shopify app config link
|
|
144
|
+
> create a new app
|
|
145
|
+
```
|
|
75
146
|
|
|
76
|
-
|
|
77
|
-
* Allowed redirection URL(s): http://localhost:3000/auth/shopify/callback
|
|
147
|
+
6. Run the default Shopify App generator to create an app that can be embedded in the Shopify Admin:
|
|
78
148
|
|
|
79
|
-
|
|
149
|
+
```sh
|
|
150
|
+
rails generate shopify_app
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
7. Run a migration to create the necessary tables in your database:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
rails db:migrate
|
|
157
|
+
```
|
|
80
158
|
|
|
81
|
-
|
|
159
|
+
8. Start the dev server and install the app
|
|
160
|
+
```
|
|
161
|
+
shopify app dev
|
|
162
|
+
```
|
|
163
|
+
Clink on the Preview URL to install the app and view it in the Shopify Admin
|
|
82
164
|
|
|
83
|
-
This app implements [OAuth 2.0](https://shopify.dev/
|
|
165
|
+
This app implements [OAuth 2.0 Token Exchange](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange) with Shopify to authenticate requests made to Shopify APIs. By default, this app is configured to use [session tokens](https://shopify.dev/concepts/apps/building-embedded-apps-using-session-tokens) to authenticate merchants when embedded in the Shopify Admin.
|
|
84
166
|
|
|
85
167
|
See [*Generators*](/docs/shopify_app/generators.md) for a complete list of generators available to Shopify App.
|
|
86
168
|
|
|
@@ -107,7 +189,6 @@ You can find documentation on gem usage, concepts, mixins, installation, and mor
|
|
|
107
189
|
* [Controller Concerns](/docs/shopify_app/controller-concerns.md)
|
|
108
190
|
* [Generators](/docs/shopify_app/generators.md)
|
|
109
191
|
* [Sessions](/docs/shopify_app/sessions.md)
|
|
110
|
-
* [Handling changes in access scopes](/docs/shopify_app/handling-access-scopes-changes.md)
|
|
111
192
|
* [Testing](/docs/shopify_app/testing.md)
|
|
112
193
|
* [Webhooks](/docs/shopify_app/webhooks.md)
|
|
113
194
|
* [Content Security Policy](/docs/shopify_app/content-security-policy.md)
|
|
@@ -161,8 +242,7 @@ ShopifyApp.configure do |config|
|
|
|
161
242
|
config.embedded_app = true
|
|
162
243
|
config.new_embedded_auth_strategy = true
|
|
163
244
|
|
|
164
|
-
#
|
|
165
|
-
# is fetched automatically when the session expires.
|
|
245
|
+
# You can enable session expiry date check so a new access token is fetched automatically when the session expires.
|
|
166
246
|
# See expiry date check docs: https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/sessions.md#expiry-date
|
|
167
247
|
config.check_session_expiry_date = true
|
|
168
248
|
...
|
data/Rakefile
CHANGED
|
@@ -6,3 +6,16 @@ require "rake/testtask"
|
|
|
6
6
|
require File.expand_path("../test/dummy/config/application", __FILE__)
|
|
7
7
|
|
|
8
8
|
Rails.application.load_tasks
|
|
9
|
+
|
|
10
|
+
# Clear Rails' test task which expects bin/rails to exist.
|
|
11
|
+
# This gem uses a dummy Rails app for testing but doesn't have bin/rails
|
|
12
|
+
# since it's a gem, not a standalone Rails application.
|
|
13
|
+
Rake::Task["test"].clear if Rake::Task.task_defined?("test")
|
|
14
|
+
|
|
15
|
+
Rake::TestTask.new(:test) do |t|
|
|
16
|
+
t.libs << "test"
|
|
17
|
+
t.pattern = "test/**/*_test.rb"
|
|
18
|
+
t.verbose = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
task default: :test
|
|
@@ -23,16 +23,8 @@ module ShopifyApp
|
|
|
23
23
|
|
|
24
24
|
return respond_with_user_token_flow if start_user_token_flow?(api_session)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
26
|
+
ShopifyApp.configuration.post_authenticate_tasks.perform(api_session)
|
|
27
|
+
|
|
36
28
|
redirect_to_app if check_billing(api_session)
|
|
37
29
|
end
|
|
38
30
|
|
|
@@ -145,35 +137,5 @@ module ShopifyApp
|
|
|
145
137
|
def user_access_scopes_strategy
|
|
146
138
|
ShopifyApp.configuration.user_access_scopes_strategy
|
|
147
139
|
end
|
|
148
|
-
|
|
149
|
-
def perform_post_authenticate_jobs(session)
|
|
150
|
-
# Ensure we use the shop session to install webhooks
|
|
151
|
-
session_for_shop = session.online? ? shop_session : session
|
|
152
|
-
|
|
153
|
-
install_webhooks(session_for_shop)
|
|
154
|
-
|
|
155
|
-
perform_after_authenticate_job(session)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def install_webhooks(session)
|
|
159
|
-
return unless ShopifyApp.configuration.has_webhooks?
|
|
160
|
-
|
|
161
|
-
WebhooksManager.queue(session.shop, session.access_token)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def perform_after_authenticate_job(session)
|
|
165
|
-
config = ShopifyApp.configuration.after_authenticate_job
|
|
166
|
-
|
|
167
|
-
return unless config && config[:job].present?
|
|
168
|
-
|
|
169
|
-
job = config[:job]
|
|
170
|
-
job = job.constantize if job.is_a?(String)
|
|
171
|
-
|
|
172
|
-
if config[:inline] == true
|
|
173
|
-
job.perform_now(shop_domain: session.shop)
|
|
174
|
-
else
|
|
175
|
-
job.perform_later(shop_domain: session.shop)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
140
|
end
|
|
179
141
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ShopifyApp
|
|
4
|
+
class ScriptTagsManagerJob < ActiveJob::Base
|
|
5
|
+
queue_as do
|
|
6
|
+
ShopifyApp.configuration.script_tags_manager_queue_name
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def perform(shop_domain:, shop_token:, script_tags:)
|
|
10
|
+
ShopifyAPI::Auth::Session.temp(shop: shop_domain, access_token: shop_token) do |session|
|
|
11
|
+
manager = ScriptTagsManager.new(script_tags, shop_domain)
|
|
12
|
+
manager.create_script_tags(session: session)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/docs/Releasing.md
CHANGED
|
@@ -1,21 +1,115 @@
|
|
|
1
1
|
# Releasing ShopifyApp
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
Before starting a release, ensure you have:
|
|
6
|
+
|
|
7
|
+
- Merged all code change PRs into main/master
|
|
8
|
+
- Access to publish the gem via Shipit
|
|
9
|
+
|
|
10
|
+
## Release Process
|
|
11
|
+
|
|
12
|
+
### Step 1: Prepare the Release Branch
|
|
13
|
+
|
|
14
|
+
1. **Ensure all feature changes are merged**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git checkout main
|
|
18
|
+
git pull origin main
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Verify: Latest commits should match GitHub's main branch.
|
|
22
|
+
|
|
23
|
+
2. **Review changes to determine version bump**
|
|
24
|
+
- Apply [semantic versioning](https://semver.org/):
|
|
25
|
+
- PATCH (X.Y.Z+1): Bug fixes only
|
|
26
|
+
- MINOR (X.Y+1.0): New features, backward compatible
|
|
27
|
+
- MAJOR (X+1.0.0): Breaking changes
|
|
28
|
+
|
|
29
|
+
### Step 2: Create Release Pull Request
|
|
30
|
+
|
|
31
|
+
1. **Create a new branch**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git checkout -b vX.Y.Z
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
2. **Update version numbers**
|
|
38
|
+
|
|
39
|
+
Edit `lib/shopify_app/version.rb`:
|
|
40
|
+
```ruby
|
|
41
|
+
module ShopifyApp
|
|
42
|
+
VERSION = "X.Y.Z" # Replace with your version
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Edit `package.json`:
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"version": "X.Y.Z" // Replace with your version
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
3. **Update dependencies**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bundle install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Expected: Gemfile.lock updates with new version.
|
|
60
|
+
|
|
61
|
+
4. **Update CHANGELOG**
|
|
62
|
+
- Add entry with the new version and date:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
## X.Y.Z (YYYY-MM-DD)
|
|
66
|
+
|
|
67
|
+
- [#PR_NUMBER](https://github.com/Shopify/shopify_app/pull/PR_NUMBER) Description of change
|
|
68
|
+
- List all changes since last release
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
5. **Create and push PR**
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git add -A
|
|
75
|
+
git commit -m "Packaging for release vX.Y.Z"
|
|
76
|
+
git push origin release-vX.Y.Z
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Title PR: "Packaging for release X.Y.Z"
|
|
80
|
+
- Add release notes to PR description
|
|
81
|
+
|
|
82
|
+
### Step 3: Tag and Publish
|
|
83
|
+
|
|
84
|
+
1. **After PR is merged, update local main**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
git checkout main
|
|
88
|
+
git pull origin main
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Verify: `git log -1` shows your merge commit.
|
|
92
|
+
|
|
93
|
+
2. **Create and push tag**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git tag -f vX.Y.Z && git push origin vX.Y.Z
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Verify: Tag appears at https://github.com/Shopify/shopify_app/tags
|
|
100
|
+
|
|
101
|
+
3. **Check Create Release workflow**
|
|
102
|
+
|
|
103
|
+
Monitor the GitHub Actions workflow to ensure it completes successfully.
|
|
104
|
+
|
|
105
|
+
4. **Publish via Shipit**
|
|
106
|
+
|
|
107
|
+
Use Shipit to build and push the gem to RubyGems.
|
|
108
|
+
|
|
109
|
+
Note: If you see an error like 'You need to create the vX.Y.X tag first', clear git cache in Shipit settings.
|
|
110
|
+
|
|
111
|
+
5. **Verify gem publication**
|
|
112
|
+
|
|
113
|
+
Check the gem on https://rubygems.org/gems/shopify_app
|
|
114
|
+
|
|
115
|
+
Expected: Shows your new version (may take 5-10 minutes).
|
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 `v23.0.0`](#upgrading-to-v2300)
|
|
12
|
+
|
|
11
13
|
[Upgrading to `v22.2.0`](#upgrading-to-v2220)
|
|
12
14
|
|
|
13
15
|
[Upgrading to `v22.0.0`](#upgrading-to-v2200)
|
|
@@ -44,6 +46,76 @@ If you do run into issues, we recommend looking at our [debugging tips.](https:/
|
|
|
44
46
|
|
|
45
47
|
## Unreleased
|
|
46
48
|
|
|
49
|
+
#### (v23.0.0) Minimum Ruby 3.2 and Rails 7.1 required, Jobs moved to app/jobs/
|
|
50
|
+
|
|
51
|
+
The minimum supported versions have been updated:
|
|
52
|
+
- **Ruby**: 3.1 → 3.2
|
|
53
|
+
- **Rails**: 5.2.1 → 7.1
|
|
54
|
+
|
|
55
|
+
Additionally, ActiveJob classes have been moved from `lib/shopify_app/jobs/` to `app/jobs/shopify_app/` to fix loading issues with modern Rails versions and follow Rails conventions.
|
|
56
|
+
|
|
57
|
+
##### Why this change was made
|
|
58
|
+
|
|
59
|
+
Rails 7.1+'s improved autoloading behavior (via Zeitwerk) properly handles jobs in the `app/jobs/` directory, loading them lazily when needed rather than eagerly during initialization.
|
|
60
|
+
|
|
61
|
+
##### Migration steps
|
|
62
|
+
|
|
63
|
+
**For most apps**: No changes needed. The jobs are internal to the gem and will be autoloaded correctly by Rails.
|
|
64
|
+
|
|
65
|
+
**If your app has custom ActiveJob serializers that reference these jobs**:
|
|
66
|
+
1. Ensure you're on Rails 7.1+ before upgrading. [Rails 7.1 Upgrade Guide](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-7-0-to-rails-7-1)
|
|
67
|
+
2. Coordinate deployment timing with apps that have custom serializers
|
|
68
|
+
3. Custom serializers will now register before jobs are loaded (correct timing)
|
|
69
|
+
|
|
70
|
+
**If your app directly requires or references job file paths** (rare):
|
|
71
|
+
```ruby
|
|
72
|
+
# ❌ Old path (will break)
|
|
73
|
+
require 'shopify_app/jobs/webhooks_manager_job'
|
|
74
|
+
|
|
75
|
+
# ✅ No require needed - Rails autoloads from app/jobs/
|
|
76
|
+
# Jobs are available as ShopifyApp::WebhooksManagerJob
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
##### Additional dependency changes
|
|
80
|
+
|
|
81
|
+
- **sprockets-rails**: Now a required runtime dependency. Most Rails apps already include this, but if your app uses an alternative asset pipeline (e.g., Propshaft), you may need to add `sprockets-rails` to your Gemfile.
|
|
82
|
+
|
|
83
|
+
#### (v23.0.0) - ShopSessionStorageWithScopes and UserSessionStorageWithScopes are deprecated
|
|
84
|
+
|
|
85
|
+
`ShopSessionStorageWithScopes` and `UserSessionStorageWithScopes` are now marked as deprecated and will be removed in v24.0.0 in favor of `ShopSessionStorage` and `UserSessionStorage`, which handle all session attributes automatically (including `access_scopes`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` for shops).
|
|
86
|
+
|
|
87
|
+
**Migration:**
|
|
88
|
+
|
|
89
|
+
1. Update your Shop model to use `ShopSessionStorage`:
|
|
90
|
+
```ruby
|
|
91
|
+
# Before
|
|
92
|
+
class Shop < ActiveRecord::Base
|
|
93
|
+
include ShopifyApp::ShopSessionStorageWithScopes
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# After
|
|
97
|
+
class Shop < ActiveRecord::Base
|
|
98
|
+
include ShopifyApp::ShopSessionStorage
|
|
99
|
+
end
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
2. Update your User model to use `UserSessionStorage`:
|
|
103
|
+
```ruby
|
|
104
|
+
# Before
|
|
105
|
+
class User < ActiveRecord::Base
|
|
106
|
+
include ShopifyApp::UserSessionStorageWithScopes
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# After
|
|
110
|
+
class User < ActiveRecord::Base
|
|
111
|
+
include ShopifyApp::UserSessionStorage
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
3. **Optional:** You can now opt-in to using expiring offline access tokens with automatic refresh. See the [Sessions documentation](/docs/shopify_app/sessions.md#offline-access-tokens) for setup instructions.
|
|
116
|
+
|
|
117
|
+
**Note:** If you had custom `access_scopes=` or `access_scopes` methods in your models, these are no longer needed. The base concerns now handle these attributes automatically.
|
|
118
|
+
|
|
47
119
|
#### (v23.0.0) - Deprecated methods in CallbackController
|
|
48
120
|
The following methods from `ShopifyApp::CallbackController` have been deprecated in `v23.0.0`
|
|
49
121
|
- `perform_after_authenticate_job`
|
|
@@ -1,10 +1,57 @@
|
|
|
1
1
|
# Content Security Policy Header
|
|
2
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
|
|
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 typically done by including the [`ShopifyApp::Authenticated`](https://github.com/Shopify/shopify_app/blob/ed41165ca9598d2c9d514487365192f22b5eb096/app/controllers/concerns/shopify_app/authenticated.rb) controller concern rather than directly including it.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Frame Ancestors
|
|
6
6
|
|
|
7
|
-
For actions that include the `ShopifyApp::FrameAncestors` controller concern, the following hosts are added to the
|
|
7
|
+
For actions that include the `ShopifyApp::FrameAncestors` controller concern, the following hosts are added to the `frame-ancestors` directive as [per the store requirements](https://shopify.dev/apps/store/security/iframe-protection#embedded-apps):
|
|
8
8
|
|
|
9
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
10
|
2. "https://admin.shopify.com"
|
|
11
|
+
|
|
12
|
+
## Strict Content Security Policy
|
|
13
|
+
|
|
14
|
+
If you enable a strict Content Security Policy in your application, you'll need to explicitly allow Shopify's App Bridge script. The gem provides a helper method to make this easy.
|
|
15
|
+
|
|
16
|
+
### Without Strict CSP (Default)
|
|
17
|
+
|
|
18
|
+
By default, Shopify app templates have CSP **disabled** (commented out in `config/initializers/content_security_policy.rb`). In this configuration:
|
|
19
|
+
- Inline scripts work (including Vite HMR for development)
|
|
20
|
+
- App Bridge loads without any configuration
|
|
21
|
+
- No `script-src` directive is set
|
|
22
|
+
|
|
23
|
+
### With Strict CSP
|
|
24
|
+
|
|
25
|
+
If you enable a strict CSP by uncommenting and configuring `content_security_policy.rb`, you must:
|
|
26
|
+
|
|
27
|
+
1. **Handle inline scripts** - Strict CSP blocks inline scripts. You can:
|
|
28
|
+
- Use `unsafe-inline` in development (for Vite HMR)
|
|
29
|
+
- Use nonces or hashes in production
|
|
30
|
+
- Move inline scripts to external files
|
|
31
|
+
|
|
32
|
+
2. **Allow App Bridge script** - Add the App Bridge script source using the provided helper:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
# config/initializers/content_security_policy.rb
|
|
36
|
+
Rails.application.configure do
|
|
37
|
+
config.content_security_policy do |policy|
|
|
38
|
+
policy.default_src :self, :https
|
|
39
|
+
|
|
40
|
+
# For development: allow inline scripts for Vite HMR
|
|
41
|
+
if Rails.env.development?
|
|
42
|
+
policy.script_src :self, :unsafe_inline
|
|
43
|
+
else
|
|
44
|
+
policy.script_src :self
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Add Shopify App Bridge script source
|
|
48
|
+
ShopifyApp.add_csp_directives(policy)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The `ShopifyApp.add_csp_directives(policy)` helper method:
|
|
54
|
+
- Adds `https://cdn.shopify.com/shopifycloud/app-bridge.js` to your `script-src` directive
|
|
55
|
+
- Preserves your existing `script-src` configuration
|
|
56
|
+
- Prevents duplicate URLs if called multiple times
|
|
57
|
+
- Is a no-op if you don't configure CSP
|
|
@@ -64,6 +64,26 @@ Implements Rails' [protect_from_forgery](https://api.rubyonrails.org/classes/Act
|
|
|
64
64
|
#### EmbeddedApp
|
|
65
65
|
If your ShopifyApp configuration has the `embedded_app` config set to true, [P3P header](https://www.w3.org/P3P/) and [content security policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) are handled for you.
|
|
66
66
|
|
|
67
|
+
##### Content Security Policy (CSP) Directives:
|
|
68
|
+
|
|
69
|
+
The EmbeddedApp concern automatically configures the following CSP directives to ensure your embedded app works correctly within Shopify Admin:
|
|
70
|
+
|
|
71
|
+
1. **frame-ancestors**: Allows the app to be embedded in iframes from:
|
|
72
|
+
- The current shop domain (e.g., `https://example.myshopify.com`)
|
|
73
|
+
- Shopify's unified admin domain (e.g., `https://admin.shopify.com`)
|
|
74
|
+
|
|
75
|
+
2. **script-src**: Allows JavaScript execution from:
|
|
76
|
+
- `'self'` - Scripts from your app's own domain
|
|
77
|
+
- `https://cdn.shopify.com/shopifycloud/app-bridge.js` - Required for App Bridge functionality
|
|
78
|
+
- Any other script sources you explicitly add in your controller
|
|
79
|
+
|
|
80
|
+
These CSP settings ensure that:
|
|
81
|
+
- Your app can be properly embedded within Shopify Admin
|
|
82
|
+
- App Bridge can load and function correctly
|
|
83
|
+
- Your app maintains security while allowing necessary Shopify integrations
|
|
84
|
+
|
|
85
|
+
##### Layout
|
|
86
|
+
|
|
67
87
|
By default, the `EmbeddedApp` concern also sets the layout file to be `app/views/layouts/embedded_app.html.erb`.
|
|
68
88
|
|
|
69
89
|
Sometimes one wants to run an embedded app in non-embedded mode. For example:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Script Tags
|
|
2
|
+
|
|
3
|
+
ShopifyApp can manage your app's [Script Tags](https://shopify.dev/docs/admin-api/graphql/reference/online-store/scripttag) for you by setting which script tags you require in the initializer.
|
|
4
|
+
> [!NOTE]
|
|
5
|
+
> Script tags should only be used for vintage themes that do not support app blocks.
|
|
6
|
+
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
ShopifyApp.configure do |config|
|
|
11
|
+
config.script_tags = [
|
|
12
|
+
# Basic script tag
|
|
13
|
+
{cache: true, src: 'https://example.com/fancy.js'},
|
|
14
|
+
|
|
15
|
+
# Script tag with template_types for app block detection
|
|
16
|
+
{
|
|
17
|
+
cache: true,
|
|
18
|
+
src: 'https://example.com/product-script.js',
|
|
19
|
+
template_types: ['product', 'collection']
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Required Scopes
|
|
26
|
+
Both the `write_script_tags` and `read_themes` scopes are required.
|
|
27
|
+
|
|
28
|
+
For apps created with the Shopify CLI, set these scopes in your `shopify.app.toml` file:
|
|
29
|
+
|
|
30
|
+
```toml
|
|
31
|
+
[access_scopes]
|
|
32
|
+
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
|
|
33
|
+
scopes = "write_products,write_script_tags,read_themes"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For older apps, you can set the scopes in the initializer:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
config.scope = 'write_products,write_script_tags,read_themes'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## How It Works
|
|
43
|
+
|
|
44
|
+
### Script Tag Creation
|
|
45
|
+
|
|
46
|
+
Script tags are created in the same way as [Webhooks](/docs/shopify_app/webhooks.md), with a background job which will create the required scripttags.
|
|
47
|
+
|
|
48
|
+
### App Block Detection
|
|
49
|
+
|
|
50
|
+
When you specify `template_types` for a script tag, ShopifyApp will check if the store's active theme supports app blocks for those template types. If any template type doesn't support app blocks, the script tags will be created as a fallback
|
|
51
|
+
|
|
52
|
+
This allows your app to automatically adapt to the store's theme capabilities, using app blocks when available and falling back to script tags when necessary.
|