Class: ShopifyAPI::Session
- Inherits:
-
Object
- Object
- ShopifyAPI::Session
- Defined in:
- lib/shopify_api/session.rb
Overview
The Shopify API authenticates each call via HTTP Authentication, using
* the application's API key as the username, and
* a hex digest of the application's shared secret and an
authentication token as the password.
Generation & acquisition of the beforementioned looks like this:
0. Developer (that's you) registers Application (and provides a
callback url) and receives an API key and a shared secret
1. User visits Application and are told they need to authenticate the
application first for read/write permission to their data (needs to
happen only once). User is asked for their shop url.
2. Application redirects to Shopify : GET <user's shop url>/admin/api/auth?api_key=<API key>
(See Session#create_permission_url)
3. User logs-in to Shopify, approves application permission request
4. Shopify redirects to the Application's callback url (provided during
registration), including the shop's name, and an authentication token in the parameters:
GET client.com/customers?shop=snake-oil.myshopify.com&t=a94a110d86d2452eb3e2af4cfb8a3828
5. Authentication password computed using the shared secret and the
authentication token (see Session#computed_password)
6. Profit!
(API calls can now authenticate through HTTP using the API key, and
computed password)
LoginController and ShopifyLoginProtection use the Session class to set Shopify::Base.site
so that all API calls are authorized transparently and end up just looking like this:
# get 3 products
@products = ShopifyAPI::Product.find(:all, :params => {:limit => 3})
# get latest 3 orders
@orders = ShopifyAPI::Order.find(:all, :params => {:limit => 3, :order => "created_at DESC" })
As an example of what your LoginController should look like, take a look
at the following:
class LoginController < ApplicationController
def index
# Ask user for their #{shop}.myshopify.com address
end
def authenticate
redirect_to ShopifyAPI::Session.new(params[:shop]).create_permission_url
end
# Shopify redirects the logged-in user back to this action along with
# the authorization token t.
#
# This token is later combined with the developer's shared secret to form
# the password used to call API methods.
def finalize
shopify_session = ShopifyAPI::Session.new(params[:shop], params[:t])
if shopify_session.valid?
session[:shopify] = shopify_session
flash[:notice] = "Logged in to shopify store."
return_address = session[:return_to] || '/home'
session[:return_to] = nil
redirect_to return_address
else
flash[:error] = "Could not log in to Shopify store."
redirect_to :action => 'index'
end
end
def logout
session[:shopify] = nil
flash[:notice] = "Successfully logged out."
redirect_to :action => 'index'
end
end
Instance Attribute Summary collapse
-
#name ⇒ Object
Returns the value of attribute name.
-
#token ⇒ Object
Returns the value of attribute token.
-
#url ⇒ Object
Returns the value of attribute url.
Class Method Summary collapse
- .prepare_url(url) ⇒ Object
- .setup(params) ⇒ Object
- .temp(domain, token, &block) ⇒ Object
- .validate_signature(params) ⇒ Object
Instance Method Summary collapse
- #create_permission_url ⇒ Object
-
#initialize(url, token = nil, params = nil) ⇒ Session
constructor
A new instance of Session.
- #shop ⇒ Object
-
#site ⇒ Object
Used by ActiveResource::Base to make all non-authentication API calls.
- #valid? ⇒ Boolean
Constructor Details
#initialize(url, token = nil, params = nil) ⇒ Session
Returns a new instance of Session.
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/shopify_api/session.rb', line 123 def initialize(url, token = nil, params = nil) self.url, self.token = url, token if params unless self.class.validate_signature(params) && params[:timestamp].to_i > 24.hours.ago.utc.to_i raise "Invalid Signature: Possible malicious login" end end self.class.prepare_url(self.url) end |
Instance Attribute Details
#name ⇒ Object
Returns the value of attribute name.
88 89 90 |
# File 'lib/shopify_api/session.rb', line 88 def name @name end |
#token ⇒ Object
Returns the value of attribute token.
88 89 90 |
# File 'lib/shopify_api/session.rb', line 88 def token @token end |
#url ⇒ Object
Returns the value of attribute url.
88 89 90 |
# File 'lib/shopify_api/session.rb', line 88 def url @url end |
Class Method Details
.prepare_url(url) ⇒ Object
108 109 110 111 112 |
# File 'lib/shopify_api/session.rb', line 108 def prepare_url(url) return nil if url.blank? url.gsub!(/https?:\/\//, '') # remove http:// or https:// url.concat(".myshopify.com") unless url.include?('.') # extend url to myshopify.com if no host is given end |
.setup(params) ⇒ Object
92 93 94 |
# File 'lib/shopify_api/session.rb', line 92 def setup(params) params.each { |k,value| send("#{k}=", value) } end |
.temp(domain, token, &block) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/shopify_api/session.rb', line 96 def temp(domain, token, &block) session = new(domain, token) original_site = ShopifyAPI::Base.site begin ShopifyAPI::Base.site = session.site yield ensure ShopifyAPI::Base.site = original_site end end |
.validate_signature(params) ⇒ Object
114 115 116 117 118 119 |
# File 'lib/shopify_api/session.rb', line 114 def validate_signature(params) return false unless signature = params[:signature] sorted_params = params.except(:signature, :action, :controller).collect{|k,v|"#{k}=#{v}"}.sort.join Digest::MD5.hexdigest(secret + sorted_params) == signature end |
Instance Method Details
#create_permission_url ⇒ Object
139 140 141 142 |
# File 'lib/shopify_api/session.rb', line 139 def return nil if url.blank? || api_key.blank? "http://#{url}/admin/api/auth?api_key=#{api_key}" end |
#site ⇒ Object
Used by ActiveResource::Base to make all non-authentication API calls
(ShopifyAPI::Base.site set in ShopifyLoginProtection#shopify_session)
147 148 149 |
# File 'lib/shopify_api/session.rb', line 147 def site "#{protocol}://#{api_key}:#{computed_password}@#{url}/admin" end |
#valid? ⇒ Boolean
151 152 153 |
# File 'lib/shopify_api/session.rb', line 151 def valid? url.present? && token.present? end |