class Koala::Facebook::OAuth
Attributes
Public Class Methods
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
@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
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
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
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
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
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
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
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
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
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
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
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
# 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
# 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
# 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
# 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
# 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