Skip to content

Commit daebcc6

Browse files
authored
Merge pull request #1197 from Shopify/revised-scope-strategies
Use access scopes strategies to handle changes to scopes requested by app
2 parents ef93fee + 7053fc4 commit daebcc6

26 files changed

+507
-23
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ You can find documentation on gem usage, concepts, mixins, installation, and mor
103103
* [Generators](/docs/shopify_app/generators.md)
104104
* [ScriptTags](/docs/shopify_app/script-tags.md)
105105
* [Session repository](/docs/shopify_app/session-repository.md)
106+
* [Handling changes in access scopes](/docs/shopify_app/handling-access-scopes-changes.md)
106107
* [Testing](/docs/shopify_app/testing.md)
107108
* [Webhooks](/docs/shopify_app/webhooks.md)
108109

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

app/controllers/shopify_app/callback_controller.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,20 @@ def start_user_token_flow?
7676
if jwt_request?
7777
false
7878
else
79-
ShopifyApp::SessionRepository.user_storage.present? && user_session.blank?
79+
return false unless ShopifyApp::SessionRepository.user_storage.present?
80+
update_user_access_scopes?
8081
end
8182
end
8283

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+
8393
def jwt_request?
8494
jwt_shopify_domain || jwt_shopify_user_id
8595
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Handling changes in access scopes
2+
The Shopify App gem provides handling changes to scopes for both shop/offline and user/online tokens. To enable your app to login via OAuth on scope changes, you can set the following configuration flag:
3+
```ruby
4+
ShopifyApp.configuration.reauth_on_access_scope_changes = true
5+
```
6+
7+
## ShopAccessScopesVerification
8+
The `ShopifyApp::ShopAccessScopesVerification` concern helps merchants grant new access scopes requested by the app. The concern compares the current access scopes granted by the shop and compares them with the scopes requested by the app. If there is a mismatch in configuration, the merchant is redirected to login via OAuth and grant the net new scopes.

docs/shopify_app/session-repository.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,11 @@ end
7878
provider :shopify,
7979
...
8080
setup: lambda { |env|
81-
...
82-
# Add this line
83-
strategy.options[:per_user_permissions] = strategy.session[:user_tokens]
84-
...
81+
configuration = ShopifyApp::OmniauthConfiguration.new(env['omniauth.strategy'], Rack::Request.new(env))
82+
configuration.build_options
8583
}
8684

8785
# In the `shopify_app.rb` initializer:
8886
config.shop_session_repository = {YOUR_SHOP_MODEL_CLASS}
8987
config.user_session_repository = {YOUR_USER_MODEL_CLASS}
90-
```
88+
```

lib/generators/shopify_app/home_controller/templates/home_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
class HomeController < AuthenticatedController
4+
include ShopifyApp::ShopAccessScopesVerification
5+
46
def index
57
@products = ShopifyAPI::Product.find(:all, params: { limit: 10 })
68
@webhooks = ShopifyAPI::Webhook.find(:all)

lib/generators/shopify_app/home_controller/templates/unauthenticated_home_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class HomeController < ApplicationController
44
include ShopifyApp::EmbeddedApp
55
include ShopifyApp::RequireKnownShop
6+
include ShopifyApp::ShopAccessScopesVerification
67

78
def index
89
@shop_origin = current_shopify_domain

lib/generators/shopify_app/install/templates/shopify_app.rb.tt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ ShopifyApp.configure do |config|
77
config.after_authenticate_job = false
88
config.api_version = "<%= @api_version %>"
99
config.shop_session_repository = 'Shop'
10+
11+
config.reauth_on_access_scope_changes = true
12+
1013
config.allow_jwt_authentication = <%= !with_cookie_authentication? %>
1114
config.allow_cookie_authentication = <%= with_cookie_authentication? %>
1215

lib/generators/shopify_app/install/templates/shopify_provider.rb.tt

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,6 @@
33
ShopifyApp.configuration.secret,
44
scope: ShopifyApp.configuration.scope,
55
setup: lambda { |env|
6-
strategy = env['omniauth.strategy']
7-
8-
shopify_auth_params = strategy.session['shopify.omniauth_params']&.with_indifferent_access
9-
shop = if shopify_auth_params.present?
10-
"https://#{shopify_auth_params[:shop]}"
11-
else
12-
''
13-
end
14-
15-
strategy.options[:client_options][:site] = shop
16-
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
17-
strategy.options[:per_user_permissions] = strategy.session[:user_tokens]
6+
configuration = ShopifyApp::OmniAuthConfiguration.new(env['omniauth.strategy'], Rack::Request.new(env))
7+
configuration.build_options
188
}

lib/shopify_app.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ def self.use_webpacker?
6161
require 'shopify_app/session/user_session_storage'
6262
require 'shopify_app/session/user_session_storage_with_scopes'
6363

64+
# access scopes strategies
65+
require 'shopify_app/access_scopes/shop_strategy'
66+
require 'shopify_app/access_scopes/user_strategy'
67+
require 'shopify_app/access_scopes/noop_strategy'
68+
6469
# omniauth_configuration
6570
require 'shopify_app/omniauth/omniauth_configuration'
6671
end

0 commit comments

Comments
 (0)