Class: OmniAuth::Strategies::Shopline
- Inherits:
-
OAuth2
- Object
- OAuth2
- OmniAuth::Strategies::Shopline
- Defined in:
- lib/omniauth/strategies/shopline.rb
Overview
OmniAuth strategy for SHOPLINE's OAuth 2.0 app authorization flow.
https://developer.shopline.com/docs/apps/api-instructions-for-use/app-authorization/
SHOPLINE deviates from plain OAuth 2 in three ways that this strategy has to handle itself rather than inherit:
- The authorize endpoint is a hash-routed admin page, so its query string sits
after the
#fragment and cannot be built byOAuth2::Client#authorize_url. - There is no
stateparameter.customFieldis the documented pass-through, so the CSRF nonce travels in it (see #verify_state). - The token endpoint authenticates with
appkey/timestamp/signheaders instead of client credentials, and signs POSTs over the request body.
Constant Summary collapse
- SITE_TEMPLATE =
"https://%<handle>s.myshopline.com"- DEFAULT_SITE =
The placeholder is replaced with the configured handle unless the consumer supplies a site of their own.
"https://{handle}.myshopline.com"- STATE_SESSION_KEY =
"omniauth.shopline.state"
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
Returns the value of attribute handle.
Instance Method Summary collapse
- #app_key ⇒ Object
- #app_secret ⇒ Object
-
#authorize_url ⇒ Object
The authorize URL is built by hand:
/admin/oauth-web/#/oauth/authorizeis a client-side route, so the query string belongs after the fragment. -
#build_access_token ⇒ Object
POST /admin/oauth/token/create, authenticated by the appkey/timestamp/sign headers rather than by client credentials, and answered with the token nested under
data. - #callback_phase ⇒ Object
-
#callback_url ⇒ Object
OmniAuth::Strategy#callback_url appends the callback request's own query string, which would send those params to SHOPLINE as part of redirect_uri and fail the registered-URL match.
-
#initialize(app, *args, &block) ⇒ Shopline
constructor
A new instance of Shopline.
- #request_phase ⇒ Object
Constructor Details
#initialize(app, *args, &block) ⇒ Shopline
Returns a new instance of Shopline.
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/omniauth/strategies/shopline.rb', line 59 def initialize(app, *args, &block) super @handle = [:handle] || raise(ArgumentError, "handle is required") site = .[:site] return unless site.nil? || site.to_s.include?("{handle}") .[:site] = format(SITE_TEMPLATE, handle: @handle) end |
Instance Attribute Details
#handle ⇒ Object (readonly)
Returns the value of attribute handle.
57 58 59 |
# File 'lib/omniauth/strategies/shopline.rb', line 57 def handle @handle end |
Instance Method Details
#app_key ⇒ Object
70 71 72 |
# File 'lib/omniauth/strategies/shopline.rb', line 70 def app_key .app_key || .client_id end |
#app_secret ⇒ Object
74 75 76 |
# File 'lib/omniauth/strategies/shopline.rb', line 74 def app_secret .app_secret || .client_secret end |
#authorize_url ⇒ Object
The authorize URL is built by hand: /admin/oauth-web/#/oauth/authorize is a
client-side route, so the query string belongs after the fragment. Handing the
path to OAuth2::Client#authorize_url would produce
/admin/oauth-web/?appKey=...#/oauth/authorize, which the page never reads.
82 83 84 85 86 87 |
# File 'lib/omniauth/strategies/shopline.rb', line 82 def = . query = URI.encode_www_form() "#{[:site]}#{[:authorize_url]}?#{query}" end |
#build_access_token ⇒ Object
POST /admin/oauth/token/create, authenticated by the appkey/timestamp/sign
headers rather than by client credentials, and answered with the token nested
under data.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/omniauth/strategies/shopline.rb', line 111 def build_access_token = body = JSON.generate(code: request.params["code"]) response = client.request( :post, .[:token_url], body: body, headers: { "Content-Type" => "application/json", "appkey" => app_key.to_s, "timestamp" => .to_s, "sign" => signature_for_body(body, ) } ) access_token_from(response) end |
#callback_phase ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/omniauth/strategies/shopline.rb', line 93 def callback_phase error = request.params["error"].to_s unless error.empty? return fail!(error.to_sym, CallbackError.new(error, request.params["error_description"])) end return fail!(:csrf_detected, CallbackError.new(:csrf_detected, "CSRF detected")) unless valid_state? unless valid_signature? return fail!(:invalid_signature, CallbackError.new(:invalid_signature, "Signature verification failed")) end super end |
#callback_url ⇒ Object
OmniAuth::Strategy#callback_url appends the callback request's own query
string, which would send those params to SHOPLINE as part of redirect_uri and
fail the registered-URL match. Note that omniauth 2's callback_path already
carries SCRIPT_NAME, so mount prefixes must not be added again.
134 135 136 |
# File 'lib/omniauth/strategies/shopline.rb', line 134 def callback_url [:callback_url] || [:redirect_uri] || (full_host + callback_path) end |
#request_phase ⇒ Object
89 90 91 |
# File 'lib/omniauth/strategies/shopline.rb', line 89 def request_phase redirect end |