shopify_app 17.0.5 → 17.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- 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 +17 -1
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +76 -0
- data/Gemfile.lock +61 -61
- data/README.md +72 -593
- data/app/controllers/concerns/shopify_app/shop_access_scopes_verification.rb +32 -0
- data/app/controllers/shopify_app/callback_controller.rb +18 -2
- data/docs/Quickstart.md +15 -77
- data/docs/Upgrading.md +110 -0
- data/docs/shopify_app/authentication.md +124 -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 +8 -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/lib/generators/shopify_app/home_controller/templates/home_controller.rb +2 -0
- data/lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb +1 -0
- data/lib/generators/shopify_app/install/install_generator.rb +30 -1
- data/lib/generators/shopify_app/install/templates/omniauth.rb +1 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +5 -2
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb.tt +8 -0
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +27 -0
- 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 +1 -1
- data/lib/generators/shopify_app/shopify_app_generator.rb +1 -1
- 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 +1 -1
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +27 -0
- data/lib/shopify_app.rb +10 -0
- 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 +22 -0
- data/lib/shopify_app/omniauth/omniauth_configuration.rb +64 -0
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +9 -7
- data/lib/shopify_app/session/in_memory_user_session_store.rb +9 -7
- data/lib/shopify_app/session/shop_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/session/user_session_storage_with_scopes.rb +58 -0
- data/lib/shopify_app/utils.rb +12 -0
- data/lib/shopify_app/version.rb +1 -1
- data/package.json +1 -1
- data/shopify_app.gemspec +1 -1
- metadata +27 -8
- data/.github/ISSUE_TEMPLATE.md +0 -19
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +0 -20
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyApp
|
4
|
+
module ShopAccessScopesVerification
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_action :login_on_scope_changes
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def login_on_scope_changes
|
14
|
+
redirect_to(shop_login) if scopes_mismatch?
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def scopes_mismatch?
|
20
|
+
ShopifyApp.configuration.shop_access_scopes_strategy.update_access_scopes?(current_shopify_domain)
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_shopify_domain
|
24
|
+
return if params[:shop].blank?
|
25
|
+
ShopifyApp::Utils.sanitize_shop_domain(params[:shop])
|
26
|
+
end
|
27
|
+
|
28
|
+
def shop_login
|
29
|
+
ShopifyApp::Utils.shop_login_url(shop: params[:shop], return_to: request.fullpath)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -76,10 +76,20 @@ module ShopifyApp
|
|
76
76
|
if jwt_request?
|
77
77
|
false
|
78
78
|
else
|
79
|
-
ShopifyApp::SessionRepository.user_storage.present?
|
79
|
+
return false unless ShopifyApp::SessionRepository.user_storage.present?
|
80
|
+
update_user_access_scopes?
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
84
|
+
def update_user_access_scopes?
|
85
|
+
return true if user_session.blank?
|
86
|
+
user_access_scopes_strategy.update_access_scopes?(user_id: session[:user_id])
|
87
|
+
end
|
88
|
+
|
89
|
+
def user_access_scopes_strategy
|
90
|
+
ShopifyApp.configuration.user_access_scopes_strategy
|
91
|
+
end
|
92
|
+
|
83
93
|
def jwt_request?
|
84
94
|
jwt_shopify_domain || jwt_shopify_user_id
|
85
95
|
end
|
@@ -118,6 +128,11 @@ module ShopifyApp
|
|
118
128
|
auth_hash['credentials']['token']
|
119
129
|
end
|
120
130
|
|
131
|
+
def access_scopes
|
132
|
+
return unless auth_hash['extra']['scope']
|
133
|
+
auth_hash['extra']['scope']
|
134
|
+
end
|
135
|
+
|
121
136
|
def reset_session_options
|
122
137
|
request.session_options[:renew] = true
|
123
138
|
session.delete(:_csrf_token)
|
@@ -127,7 +142,8 @@ module ShopifyApp
|
|
127
142
|
session_store = ShopifyAPI::Session.new(
|
128
143
|
domain: shop_name,
|
129
144
|
token: token,
|
130
|
-
api_version: ShopifyApp.configuration.api_version
|
145
|
+
api_version: ShopifyApp.configuration.api_version,
|
146
|
+
access_scopes: access_scopes
|
131
147
|
)
|
132
148
|
|
133
149
|
session[:shopify_user] = associated_user
|
data/docs/Quickstart.md
CHANGED
@@ -1,93 +1,31 @@
|
|
1
|
-
Quickstart
|
2
|
-
==========
|
1
|
+
# Quickstart
|
3
2
|
|
4
|
-
|
5
|
-
This guide assumes you have Ruby, Rails and PostgreSQL installed on your computer already; if you haven't done that already start with [this guide.](https://guides.rubyonrails.org/v5.0/getting_started.html#installing-rails)
|
3
|
+
This guide assumes you have completed the steps to create a new Rails app using the Shopify App gem found in the [*Usage*](/README.md#usage) section of the project's [*README*](/README.md).
|
6
4
|
|
7
|
-
|
8
|
-
--------------------------------
|
5
|
+
#### Table of contents
|
9
6
|
|
10
|
-
|
7
|
+
[Make your app available to the internet](#make-your-app-available-to-the-internet)
|
11
8
|
|
12
|
-
|
13
|
-
$ rails new test-app --database=postgresql
|
14
|
-
$ cd test-app
|
15
|
-
$ git init
|
16
|
-
$ git add .
|
17
|
-
$ git commit -m 'new rails app'
|
18
|
-
```
|
19
|
-
|
20
|
-
2. Create a new Heroku app
|
21
|
-
--------------------------
|
22
|
-
|
23
|
-
The next step is to create a new Heroku app to host your application. If you haven't got a Heroku account yet, create a free account [here](https://www.heroku.com/).
|
24
|
-
|
25
|
-
Head to the Heroku dashboard and create a new app, or run the following commands with the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli#download-and-install) installed, substituting `name` for the name of your own app:
|
26
|
-
|
27
|
-
CLI:
|
28
|
-
```sh
|
29
|
-
$ heroku create name
|
30
|
-
```
|
31
|
-
|
32
|
-
3. Create a new App in the Shopify Partner dashboard
|
33
|
-
-----------------------------------------
|
34
|
-
* Create a Shopify app in the [Partners dashboard](https://partner.shopify.com). For this tutorial, you can choose either a public or custom app, but you can [learn about App Types here.](https://help.shopify.com/en/manual/apps/app-types)
|
35
|
-
[https://app.shopify.com/services/partners/api_clients](https://app.shopify.com/services/partners/api_clients)
|
36
|
-
* Set the callback url to `https://<appname>.herokuapp.com/`
|
37
|
-
* Choose an embedded app
|
38
|
-
* Set the app's `redirect_uri` to `https://<appname>.herokuapp.com/auth/shopify/callback`
|
39
|
-
|
40
|
-
4. Add ShopifyApp to Gemfile
|
41
|
-
----------------------------
|
42
|
-
|
43
|
-
Run this command to add the `shopify_app` Gem to your app:
|
9
|
+
[Use Shopify App Bridge to embed your app in the Shopify Admin](#use-shopify-app-bridge-to-embed-your-app-in-the-shopify-admin)
|
44
10
|
|
45
|
-
|
46
|
-
$ bundle add shopify_app
|
47
|
-
```
|
11
|
+
## Make your app available to the internet
|
48
12
|
|
49
|
-
|
13
|
+
Your local app needs to be accessible from the public Internet in order to install it on a Shopify store, to use the [App Proxy Controller](/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb) or receive [webhooks](/docs/shopify_app/webhooks.md).
|
50
14
|
|
51
|
-
|
52
|
-
-------------------------------
|
15
|
+
Use a tunneling service like [ngrok](https://ngrok.com/), [Beeceptor](https://beeceptor.com/), [Mockbin](http://mockbin.org/), or [Hookbin](https://hookbin.com/) to make your development environment accessible to the internet.
|
53
16
|
|
54
|
-
|
17
|
+
For example with [ngrok](https://ngrok.com/), run this command to set up a tunnel proxy to Rails' default port:
|
55
18
|
|
56
19
|
```sh
|
57
|
-
|
58
|
-
$ rails generate shopify_app
|
59
|
-
$ git add .
|
60
|
-
$ git commit -m 'generated shopify app'
|
20
|
+
ngrok http 3000
|
61
21
|
```
|
62
22
|
|
63
|
-
|
64
|
-
README for further details on how to set this up.
|
65
|
-
|
66
|
-
6. Deploy your app
|
67
|
-
---------
|
68
|
-
|
69
|
-
Once you've generated your app, push it into your Heroku environment to see it up and running:
|
70
|
-
```sh
|
71
|
-
$ git push heroku
|
72
|
-
$ heroku run rake db:migrate
|
73
|
-
```
|
74
|
-
|
75
|
-
7. Install the App!
|
76
|
-
-------------------
|
77
|
-
|
78
|
-
Ensure you have created a [development store](https://help.shopify.com/en/api/getting-started/making-your-first-request#create-a-development-store) using the Shopify Partner Dashboard. If you don't already have one, [create one by following these instructions](https://help.shopify.com/en/api/getting-started/making-your-first-request#create-a-development-store).
|
79
|
-
|
80
|
-
##### Note: The following step will cause your store to become `transfer-disabled.` Read more about store transfer and why it's important [here](https://help.shopify.com/en/api/guides/store-transfers#transfer-disabled-stores). This is an irreversible change, so be sure you don't plan to transfer this store to a merchant.
|
81
|
-
|
82
|
-
Install the app onto your new development store using the Partner Dashboard. Log in to your account, visit the apps page, click the app you created earlier, and looking for the `Test your app` instructions where you can select a store to install your app on.
|
83
|
-
|
84
|
-
![Installing an app on the partners dashboard dropdown](/docs/install-on-dev-shop.png)
|
23
|
+
See the [*Embed the app in Shopify*](https://shopify.dev/tutorials/build-rails-react-app-that-uses-app-bridge-authentication#embed-the-app-in-shopify) section of [*Build a Shopify app with Rails, React, and App Bridge*](https://shopify.dev/tutorials/build-rails-react-app-that-uses-app-bridge-authentication) to learn more.
|
85
24
|
|
86
|
-
|
25
|
+
## Use Shopify App Bridge to embed your app in the Shopify Admin
|
87
26
|
|
88
|
-
|
27
|
+
A basic example of using [*Shopify App Bridge*](https://shopify.dev/tools/app-bridge) is included in the install generator. An instance Shopify App Bridge is automatically initialized in [shopify_app.js](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/shopify_app.js).
|
89
28
|
|
90
|
-
|
91
|
-
-------------------
|
29
|
+
The [flash_messages.js](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/flash_messages.js) file converts Rails [flash messages](https://api.rubyonrails.org/classes/ActionDispatch/Flash.html) to App Bridge Toast actions automatically. By default, this library is included via [unpkg in the embedded_app layout](https://github.com/Shopify/shopify_app/blob/master/lib/generators/shopify_app/install/templates/embedded_app.html.erb#L27).
|
92
30
|
|
93
|
-
|
31
|
+
For more advanced uses it is recommended to [install App Bridge via npm or yarn](https://help.shopify.com/en/api/embedded-apps/app-bridge/getting-started#set-up-shopify-app-bridge-in-your-app).
|
data/docs/Upgrading.md
ADDED
@@ -0,0 +1,110 @@
|
|
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 `v13.0.0`](#upgrading-to-v1300)
|
8
|
+
|
9
|
+
[Upgrading to `v11.7.0`](#upgrading-to-v1170)
|
10
|
+
|
11
|
+
[Upgrading from `v8.6` to `v9.0.0`](#upgrading-from-v86-to-v900)
|
12
|
+
|
13
|
+
## Upgrading to `v13.0.0`
|
14
|
+
|
15
|
+
Version 13.0.0 adds the ability to use both user and shop sessions, concurrently. This however involved a large
|
16
|
+
change to how session stores work. Here are the steps to migrate to 13.x
|
17
|
+
|
18
|
+
### Changes to `config/initializers/shopify_app.rb`
|
19
|
+
|
20
|
+
- *REMOVE* `config.per_user_tokens = [true|false]` this is no longer needed
|
21
|
+
- *CHANGE* `config.session_repository = 'Shop'` To `config.shop_session_repository = 'Shop'`
|
22
|
+
- *ADD (optional)* User Session Storage `config.user_session_repository = 'User'`
|
23
|
+
|
24
|
+
### Shop Model Changes (normally `app/models/shop.rb`)
|
25
|
+
|
26
|
+
- *CHANGE* `include ShopifyApp::SessionStorage` to `include ShopifyApp::ShopSessionStorage`
|
27
|
+
|
28
|
+
### Changes to the @shop_session instance variable (normally in `app/controllers/*.rb`)
|
29
|
+
|
30
|
+
- *CHANGE* if you are using shop sessions, `@shop_session` will need to be changed to `@current_shopify_session`.
|
31
|
+
|
32
|
+
### Changes to Rails `session`
|
33
|
+
|
34
|
+
- *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.
|
35
|
+
|
36
|
+
### Changes to `ShopifyApp::LoginProtection`
|
37
|
+
|
38
|
+
`ShopifyApp::LoginProtection`
|
39
|
+
|
40
|
+
- CHANGE if you are using `ShopifyApp::LoginProtection#shopify_session` in your code, it will need to be
|
41
|
+
changed to `ShopifyApp::LoginProtection#activate_shopify_session`
|
42
|
+
- CHANGE if you are using `ShopifyApp::LoginProtection#clear_shop_session` in your code, it will need to be
|
43
|
+
changed to `ShopifyApp::LoginProtection#clear_shopify_session`
|
44
|
+
|
45
|
+
### Notes
|
46
|
+
You do not need a user model; a shop session is fine for most applications.
|
47
|
+
|
48
|
+
---
|
49
|
+
|
50
|
+
## Upgrading to `v11.7.0`
|
51
|
+
|
52
|
+
### Session storage method signature breaking change
|
53
|
+
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.
|
54
|
+
|
55
|
+
---
|
56
|
+
|
57
|
+
## Upgrading from `v8.6` to `v9.0.0`
|
58
|
+
|
59
|
+
### Configuration change
|
60
|
+
|
61
|
+
Add an API version configuration in `config/initializers/shopify_app.rb`
|
62
|
+
Set this to the version you want to run against by default. See [Shopify API docs](https://help.shopify.com/en/api/versioning) for versions available.
|
63
|
+
```ruby
|
64
|
+
config.api_version = '2019-04'
|
65
|
+
```
|
66
|
+
|
67
|
+
### Session storage change
|
68
|
+
|
69
|
+
You will need to add an `api_version` method to your session storage object. The default implementation for this is.
|
70
|
+
```ruby
|
71
|
+
def api_version
|
72
|
+
ShopifyApp.configuration.api_version
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
### Generated file change
|
77
|
+
|
78
|
+
`embedded_app.html.erb` the usage of `shop_session.url` needs to be changed to `shop_session.domain`
|
79
|
+
```erb
|
80
|
+
<script type="text/javascript">
|
81
|
+
ShopifyApp.init({
|
82
|
+
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
83
|
+
|
84
|
+
shopOrigin: "<%= "https://#{ @shop_session.url }" if @shop_session %>",
|
85
|
+
|
86
|
+
debug: false,
|
87
|
+
forceRedirect: true
|
88
|
+
});
|
89
|
+
</script>
|
90
|
+
```
|
91
|
+
is changed to
|
92
|
+
```erb
|
93
|
+
<script type="text/javascript">
|
94
|
+
ShopifyApp.init({
|
95
|
+
apiKey: "<%= ShopifyApp.configuration.api_key %>",
|
96
|
+
|
97
|
+
shopOrigin: "<%= "https://#{ @shop_session.domain }" if @shop_session %>",
|
98
|
+
|
99
|
+
debug: false,
|
100
|
+
forceRedirect: true
|
101
|
+
});
|
102
|
+
</script>
|
103
|
+
```
|
104
|
+
|
105
|
+
### ShopifyAPI changes
|
106
|
+
|
107
|
+
You will need to also follow the ShopifyAPI [upgrade guide](https://github.com/Shopify/shopify_api/blob/master/README.md#-breaking-change-notice-for-version-700-) to ensure your app is ready to work with API versioning.
|
108
|
+
|
109
|
+
[dashboard]:https://partners.shopify.com
|
110
|
+
[app-bridge]:https://help.shopify.com/en/api/embedded-apps/app-bridge
|
@@ -0,0 +1,124 @@
|
|
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
|
+
### `ShopifyApp::EnsureAuthenticatedLinks`
|
110
|
+
|
111
|
+
The [`ShopifyApp::EnsureAuthenticatedLinks`](/app/controllers/concerns/shopify_app/ensure_authenticated_links.rb) concern helps authenticate users that access protected pages of your app directly.
|
112
|
+
|
113
|
+
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.
|
114
|
+
|
115
|
+
*Example:*
|
116
|
+
|
117
|
+
```rb
|
118
|
+
class AuthenticatedController < ApplicationController
|
119
|
+
include ShopifyApp::EnsureAuthenticatedLinks
|
120
|
+
include ShopifyApp::Authenticated
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
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,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://my.domain.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://your_app_website.com/app_proxy`.
|
81
|
+
|
82
|
+
![Creating an App Proxy](/images/app-proxy-screenshot.png)
|