class Koala::Facebook::OAuth

Attributes

app_id[R]
app_secret[R]
oauth_callback_url[R]

Public Class Methods

new(app_id = nil, app_secret = nil, oauth_callback_url = nil) click to toggle source

Creates a new OAuth client.

@param app_id [String, Integer] a Facebook application ID @param app_secret a Facebook application secret @param oauth_callback_url the URL in your app to which users authenticating with OAuth will be sent

   # File lib/koala/oauth.rb
15 def initialize(app_id = nil, app_secret = nil, oauth_callback_url = nil)
16   @app_id = app_id || Koala.config.app_id
17   @app_secret = app_secret || Koala.config.app_secret
18   @oauth_callback_url = oauth_callback_url || Koala.config.oauth_callback_url
19 end

Public Instance Methods

exchange_access_token(access_token, options = {}) click to toggle source

@see exchange_access_token_info

@param (see exchange_access_token_info)

@return A new access token or the existing one, set to expire in 60 days.

    # File lib/koala/oauth.rb
225 def exchange_access_token(access_token, options = {})
226   if info = exchange_access_token_info(access_token, options)
227     info["access_token"]
228   end
229 end
exchange_access_token_info(access_token, options = {}) click to toggle source

Fetches an access_token with extended expiration time, along with any other information provided by Facebook. See developers.facebook.com/docs/offline-access-deprecation/#extend_token (search for fb_exchange_token).

@param access_token the access token to exchange @param options any additional parameters to send to Facebook when exchanging tokens.

@return the access token with extended expiration time and other information (expiration, etc.)

    # File lib/koala/oauth.rb
211 def exchange_access_token_info(access_token, options = {})
212   get_token_from_server({
213     :grant_type => 'fb_exchange_token',
214     :fb_exchange_token => access_token
215   }, true, options)
216 end
generate_client_code(access_token) click to toggle source

Generates a 'client code' from a server side long-lived access token. With the generated code, it can be sent to a client application which can then use it to get a long-lived access token from Facebook. After which the clients can use that access token to make requests to Facebook without having to use the server token, yet the server access token remains valid. See developers.facebook.com/docs/facebook-login/access-tokens/#long-via-code

@param access_token a user's long lived (server) access token

@raise Koala::Facebook::ServerError if Facebook returns a server error (status >= 500) @raise Koala::Facebook::OAuthTokenRequestError if Facebook returns an error response (status >= 400) @raise Koala::Facebook::BadFacebookResponse if Facebook returns a blank response @raise Koala::KoalaError if response does not contain 'code' hash key

@return a string of the generated 'code'

    # File lib/koala/oauth.rb
130 def generate_client_code(access_token)
131   response = fetch_token_string({:redirect_uri => @oauth_callback_url, :access_token => access_token}, false, 'client_code')
132 
133   # Facebook returns an empty body in certain error conditions
134   if response == ''
135     raise BadFacebookResponse.new(200, '', 'generate_client_code received an error: empty response body')
136   else
137     result = JSON.parse(response)
138   end
139 
140   result.has_key?('code') ? result['code'] : raise(Koala::KoalaError.new("Facebook returned a valid response without the expected 'code' in the body (response = #{response})"))
141 end
get_access_token(code, options = {}) click to toggle source

Fetches the access token (ignoring expiration and other info) from Facebook. Useful when you've received an OAuth code using the server-side authentication process. @see get_access_token_info

@note (see url_for_oauth_code)

@param (see get_access_token_info)

@raise (see get_access_token_info)

@return the access token

    # File lib/koala/oauth.rb
174 def get_access_token(code, options = {})
175   # upstream methods will throw errors if needed
176   if info = get_access_token_info(code, options)
177     string = info["access_token"]
178   end
179 end
get_access_token_info(code, options = {}) click to toggle source

Fetches an access token, token expiration, and other info from Facebook. Useful when you've received an OAuth code using the server-side authentication process. @see url_for_oauth_code

@note (see url_for_oauth_code)

@param code (see url_for_access_token) @param options any additional parameters to send to Facebook when redeeming the token

@raise Koala::Facebook::OAuthTokenRequestError if Facebook returns an error response

@return a hash of the access token info returned by Facebook (token, expiration, etc.)

    # File lib/koala/oauth.rb
157 def get_access_token_info(code, options = {})
158   # convenience method to get a parsed token from Facebook for a given code
159   # should this require an OAuth callback URL?
160   get_token_from_server({:code => code, :redirect_uri => options[:redirect_uri] || @oauth_callback_url}, false, options)
161 end
get_app_access_token(options = {}) click to toggle source

Fetches the application's access token (ignoring expiration and other info). @see get_app_access_token_info

@param (see get_app_access_token_info)

@return the application access token

    # File lib/koala/oauth.rb
198 def get_app_access_token(options = {})
199   if info = get_app_access_token_info(options)
200     info["access_token"]
201   end
202 end
get_app_access_token_info(options = {}) click to toggle source

Fetches the application's access token, along with any other information provided by Facebook. See developers.facebook.com/docs/authentication/ (search for App Login).

@param options any additional parameters to send to Facebook when redeeming the token

@return the application access token and other information (expiration, etc.)

    # File lib/koala/oauth.rb
187 def get_app_access_token_info(options = {})
188   # convenience method to get a the application's sessionless access token
189   get_token_from_server({:grant_type => 'client_credentials'}, true, options)
190 end
get_user_info_from_cookies(cookie_hash) click to toggle source

Parses the cookie set Facebook's JavaScript SDK.

@note this method can only be called once per session, as the OAuth code

Facebook supplies can only be redeemed once.  Your application
must handle cross-request storage of this information; you can no
longer call this method multiple times.  (This works out, as the
method has to make a call to FB's servers anyway, which you don't
want on every call.)

@param cookie_hash a set of cookies that includes the Facebook cookie.

You can pass Rack/Rails/Sinatra's cookie hash directly to this method.

@return the authenticated user's information as a hash, or nil.

   # File lib/koala/oauth.rb
34 def get_user_info_from_cookies(cookie_hash)
35   if signed_cookie = cookie_hash["fbsr_#{@app_id}"]
36     parse_signed_cookie(signed_cookie)
37   elsif unsigned_cookie = cookie_hash["fbs_#{@app_id}"]
38     parse_unsigned_cookie(unsigned_cookie)
39   end
40 end
Also aliased as: get_user_info_from_cookie
parse_signed_request(input) click to toggle source

Parses a signed request string provided by Facebook to canvas apps or in a secure cookie.

@param input the signed request from Facebook

@raise OAuthSignatureError if the signature is incomplete, invalid, or using an unsupported algorithm

@return a hash of the validated request information

    # File lib/koala/oauth.rb
238 def parse_signed_request(input)
239   encoded_sig, encoded_envelope = input.split('.', 2)
240   raise OAuthSignatureError, 'Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope
241 
242   signature = base64_url_decode(encoded_sig).unpack("H*").first
243   envelope = JSON.parse(base64_url_decode(encoded_envelope))
244 
245   raise OAuthSignatureError, "Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
246 
247   # now see if the signature is valid (digest, key, data)
248   hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @app_secret, encoded_envelope)
249   raise OAuthSignatureError, 'Invalid signature' if (signature != hmac)
250 
251   envelope
252 end
url_for_access_token(code, options = {}) click to toggle source

Once you receive an OAuth code, you need to redeem it from Facebook using an appropriate URL. (This is done by your server behind the scenes.) See developers.facebook.com/docs/authentication/.

@see url_for_oauth_code

@note (see url_for_oauth_code)

@param code an OAuth code received from Facebook @param options any additional query parameters to add to the URL

@raise (see url_for_oauth_code)

@return an URL your server can query for the user's access token

   # File lib/koala/oauth.rb
90 def url_for_access_token(code, options = {})
91   # Creates the URL for the token corresponding to a given code generated by Facebook
92   url_options = {
93     :client_id => @app_id,
94     :code => code,
95     :client_secret => @app_secret
96   }.merge(options)
97   build_url(:graph_server, "/oauth/access_token", true, url_options)
98 end
url_for_dialog(dialog_type, options = {}) click to toggle source

Builds a URL for a given dialog (feed, friends, OAuth, pay, send, etc.) See developers.facebook.com/docs/reference/dialogs/.

@note (see url_for_oauth_code)

@param dialog_type the kind of Facebook dialog you want to show @param options any additional query parameters to add to the URL

@return an URL your server can query for the user's access token

    # File lib/koala/oauth.rb
109 def url_for_dialog(dialog_type, options = {})
110   # some endpoints require app_id, some client_id, supply both doesn't seem to hurt
111   url_options = {:app_id => @app_id, :client_id => @app_id}.merge(options)
112   build_url(:dialog_host, "/dialog/#{dialog_type}", true, url_options)
113 end
url_for_oauth_code(options = {}) click to toggle source

Builds an OAuth URL, where users will be prompted to log in and for any desired permissions. When the users log in, you receive a callback with their See developers.facebook.com/docs/authentication/.

@see url_for_access_token

@note The server-side authentication and dialog methods should only be used

if your application can't use the Facebook Javascript SDK,
which provides a much better user experience.
See http://developers.facebook.com/docs/reference/javascript/.

@param options any query values to add to the URL, as well as any special/required values listed below. @option options permissions an array or comma-separated string of desired permissions @option options state a unique string to serve as a CSRF (cross-site request

forgery) token -- highly recommended for security. See
https://developers.facebook.com/docs/howtos/login/server-side-login/

@raise ArgumentError if no OAuth callback was specified in OAuth#new or in options as :redirect_uri

@return an OAuth URL you can send your users to

   # File lib/koala/oauth.rb
65 def url_for_oauth_code(options = {})
66   # for permissions, see http://developers.facebook.com/docs/authentication/permissions
67   if permissions = options.delete(:permissions)
68     options[:scope] = permissions.is_a?(Array) ? permissions.join(",") : permissions
69   end
70   url_options = {:client_id => @app_id}.merge(options)
71 
72   # Creates the URL for oauth authorization for a given callback and optional set of permissions
73   build_url(:dialog_host, "/dialog/oauth", true, url_options)
74 end

Protected Instance Methods

base64_url_decode(str) click to toggle source

base 64 directly from github.com/facebook/crypto-request-examples/raw/master/sample.rb

    # File lib/koala/oauth.rb
319 def base64_url_decode(str)
320   str += '=' * (4 - str.length.modulo(4))
321   Base64.decode64(str.tr('-_', '+/'))
322 end
build_url(type, path, require_redirect_uri = false, url_options = {}) click to toggle source
    # File lib/koala/oauth.rb
333 def build_url(type, path, require_redirect_uri = false, url_options = {})
334   if require_redirect_uri && !(url_options[:redirect_uri] ||= url_options.delete(:callback) || @oauth_callback_url)
335     raise ArgumentError, "build_url must get a callback either from the OAuth object or in the parameters!"
336   end
337   params = Koala::HTTPService.encode_params(url_options)
338   "#{server_url(type)}#{path}?#{params}"
339 end
fetch_token_string(args, post = false, endpoint = "access_token", options = {}) click to toggle source
    # File lib/koala/oauth.rb
305 def fetch_token_string(args, post = false, endpoint = "access_token", options = {})
306   response = Koala.make_request("/oauth/#{endpoint}", {
307     :client_id => @app_id,
308     :client_secret => @app_secret
309   }.merge!(args), post ? "post" : "get", {:use_ssl => true}.merge!(options))
310 
311   raise ServerError.new(response.status, response.body) if response.status >= 500
312   raise OAuthTokenRequestError.new(response.status, response.body) if response.status >= 400
313 
314   response.body
315 end
get_token_from_server(args, post = false, options = {}) click to toggle source
    # File lib/koala/oauth.rb
256 def get_token_from_server(args, post = false, options = {})
257   # fetch the result from Facebook's servers
258   response = fetch_token_string(args, post, "access_token", options)
259   parse_access_token(response)
260 end
parse_access_token(response_text) click to toggle source
    # File lib/koala/oauth.rb
262 def parse_access_token(response_text)
263   JSON.parse(response_text)
264 rescue JSON::ParserError
265   response_text.split("&").inject({}) do |hash, bit|
266     key, value = bit.split("=")
267     hash.merge!(key => value)
268   end
269 end
server_url(type) click to toggle source
    # File lib/koala/oauth.rb
324 def server_url(type)
325   url = "https://#{Koala.config.send(type)}"
326   if version = Koala.config.api_version
327     "#{url}/#{version}"
328   else
329     url
330   end
331 end