omniauth-facebook-3.0.0/0000755000004100000410000000000012624164072015141 5ustar www-datawww-dataomniauth-facebook-3.0.0/Rakefile0000644000004100000410000000026312624164072016607 0ustar www-datawww-datarequire 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new do |task| task.libs << 'test' task.test_files = FileList['test/*_test.rb'] end task :default => :test omniauth-facebook-3.0.0/Gemfile0000644000004100000410000000012712624164072016434 0ustar www-datawww-datasource 'https://rubygems.org' gemspec platforms :rbx do gem 'rubysl', '~> 2.0' end omniauth-facebook-3.0.0/.travis.yml0000644000004100000410000000033512624164072017253 0ustar www-datawww-databefore_install: - gem update bundler - bundle --version - gem update --system 2.1.11 - gem --version rvm: - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 - 2.1 - jruby - rbx matrix: allow_failures: - rvm: rbx omniauth-facebook-3.0.0/lib/0000755000004100000410000000000012624164072015707 5ustar www-datawww-dataomniauth-facebook-3.0.0/lib/omniauth/0000755000004100000410000000000012624164072017533 5ustar www-datawww-dataomniauth-facebook-3.0.0/lib/omniauth/strategies/0000755000004100000410000000000012624164072021705 5ustar www-datawww-dataomniauth-facebook-3.0.0/lib/omniauth/strategies/facebook.rb0000644000004100000410000001411112624164072024001 0ustar www-datawww-datarequire 'omniauth/strategies/oauth2' require 'omniauth/facebook/signed_request' require 'openssl' require 'rack/utils' require 'uri' module OmniAuth module Strategies class Facebook < OmniAuth::Strategies::OAuth2 class NoAuthorizationCodeError < StandardError; end DEFAULT_SCOPE = 'email' option :client_options, { :site => 'https://graph.facebook.com', :authorize_url => "https://www.facebook.com/dialog/oauth", :token_url => 'oauth/access_token' } option :token_params, { :parse => :query } option :access_token_options, { :header_format => 'OAuth %s', :param_name => 'access_token' } option :authorize_options, [:scope, :display, :auth_type] uid { raw_info['id'] } info do prune!({ 'nickname' => raw_info['username'], 'email' => raw_info['email'], 'name' => raw_info['name'], 'first_name' => raw_info['first_name'], 'last_name' => raw_info['last_name'], 'image' => image_url(uid, options), 'description' => raw_info['bio'], 'urls' => { 'Facebook' => raw_info['link'], 'Website' => raw_info['website'] }, 'location' => (raw_info['location'] || {})['name'], 'verified' => raw_info['verified'] }) end extra do hash = {} hash['raw_info'] = raw_info unless skip_info? prune! hash end def raw_info @raw_info ||= access_token.get('me', info_options).parsed || {} end def info_options params = {:appsecret_proof => appsecret_proof} params.merge!({:fields => (options[:info_fields] || 'name,email')}) params.merge!({:locale => options[:locale]}) if options[:locale] { :params => params } end def callback_phase with_authorization_code! do super end rescue NoAuthorizationCodeError => e fail!(:no_authorization_code, e) rescue OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError => e fail!(:unknown_signature_algorithm, e) end # NOTE If we're using code from the signed request then FB sets the redirect_uri to '' during the authorize # phase and it must match during the access_token phase: # https://github.com/facebook/facebook-php-sdk/blob/master/src/base_facebook.php#L477 def callback_url if @authorization_code_from_signed_request_in_cookie '' else # Fixes regression in omniauth-oauth2 v1.4.0 by https://github.com/intridea/omniauth-oauth2/commit/85fdbe117c2a4400d001a6368cc359d88f40abc7 options[:callback_url] || (full_host + script_name + callback_path) end end def access_token_options options.access_token_options.inject({}) { |h,(k,v)| h[k.to_sym] = v; h } end # You can pass +display+, +scope+, or +auth_type+ params to the auth request, if you need to set them dynamically. # You can also set these options in the OmniAuth config :authorize_params option. # # For example: /auth/facebook?display=popup def authorize_params super.tap do |params| %w[display scope auth_type].each do |v| if request.params[v] params[v.to_sym] = request.params[v] end end params[:scope] ||= DEFAULT_SCOPE end end protected def build_access_token super.tap do |token| token.options.merge!(access_token_options) end end private def signed_request_from_cookie @signed_request_from_cookie ||= raw_signed_request_from_cookie && OmniAuth::Facebook::SignedRequest.parse(raw_signed_request_from_cookie, client.secret) end def raw_signed_request_from_cookie request.cookies["fbsr_#{client.id}"] end # Picks the authorization code in order, from: # # 1. The request 'code' param (manual callback from standard server-side flow) # 2. A signed request from cookie (passed from the client during the client-side flow) def with_authorization_code! if request.params.key?('code') yield elsif code_from_signed_request = signed_request_from_cookie && signed_request_from_cookie['code'] request.params['code'] = code_from_signed_request @authorization_code_from_signed_request_in_cookie = true # NOTE The code from the signed fbsr_XXX cookie is set by the FB JS SDK will confirm that the identity of the # user contained in the signed request matches the user loading the app. original_provider_ignores_state = options.provider_ignores_state options.provider_ignores_state = true begin yield ensure request.params.delete('code') @authorization_code_from_signed_request_in_cookie = false options.provider_ignores_state = original_provider_ignores_state end else raise NoAuthorizationCodeError, 'must pass either a `code` (via URL or by an `fbsr_XXX` signed request cookie)' end end def prune!(hash) hash.delete_if do |_, value| prune!(value) if value.is_a?(Hash) value.nil? || (value.respond_to?(:empty?) && value.empty?) end end def image_url(uid, options) uri_class = options[:secure_image_url] ? URI::HTTPS : URI::HTTP site_uri = URI.parse(client.site) url = uri_class.build({:host => site_uri.host, :path => "#{site_uri.path}/#{uid}/picture"}) query = if options[:image_size].is_a?(String) || options[:image_size].is_a?(Symbol) { :type => options[:image_size] } elsif options[:image_size].is_a?(Hash) options[:image_size] end url.query = Rack::Utils.build_query(query) if query url.to_s end def appsecret_proof @appsecret_proof ||= OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, client.secret, access_token.token) end end end end omniauth-facebook-3.0.0/lib/omniauth/facebook/0000755000004100000410000000000012624164072021304 5ustar www-datawww-dataomniauth-facebook-3.0.0/lib/omniauth/facebook/signed_request.rb0000644000004100000410000000253612624164072024660 0ustar www-datawww-datarequire 'openssl' module OmniAuth module Facebook class SignedRequest class UnknownSignatureAlgorithmError < NotImplementedError; end SUPPORTED_ALGORITHM = 'HMAC-SHA256' attr_reader :value, :secret def self.parse(value, secret) new(value, secret).payload end def initialize(value, secret) @value = value @secret = secret end def payload @payload ||= parse_signed_request end private def parse_signed_request signature, encoded_payload = value.split('.') return if signature.nil? decoded_hex_signature = base64_decode_url(signature) decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload)) unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}" end if valid_signature?(decoded_hex_signature, encoded_payload) decoded_payload end end def valid_signature?(signature, payload, algorithm = OpenSSL::Digest::SHA256.new) OpenSSL::HMAC.digest(algorithm, secret, payload) == signature end def base64_decode_url(value) value += '=' * (4 - value.size.modulo(4)) Base64.decode64(value.tr('-_', '+/')) end end end end omniauth-facebook-3.0.0/lib/omniauth/facebook/version.rb0000644000004100000410000000010212624164072023307 0ustar www-datawww-datamodule OmniAuth module Facebook VERSION = "3.0.0" end end omniauth-facebook-3.0.0/lib/omniauth/facebook.rb0000644000004100000410000000011312624164072021624 0ustar www-datawww-datarequire 'omniauth/facebook/version' require 'omniauth/strategies/facebook' omniauth-facebook-3.0.0/lib/omniauth-facebook.rb0000644000004100000410000000003412624164072021624 0ustar www-datawww-datarequire 'omniauth/facebook' omniauth-facebook-3.0.0/metadata.yml0000644000004100000410000000601012624164072017441 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: omniauth-facebook version: !ruby/object:Gem::Version version: 3.0.0 platform: ruby authors: - Mark Dodwell - Josef Šimánek autorequire: bindir: bin cert_chain: [] date: 2015-10-27 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: omniauth-oauth2 requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.2' - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: mocha requirement: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' description: email: - mark@madeofcode.com - retro@ballgag.cz executables: [] extensions: [] extra_rdoc_files: [] files: - .gitignore - .travis.yml - CHANGELOG.md - Gemfile - README.md - Rakefile - example/Gemfile - example/Gemfile.lock - example/app.rb - example/config.ru - lib/omniauth-facebook.rb - lib/omniauth/facebook.rb - lib/omniauth/facebook/signed_request.rb - lib/omniauth/facebook/version.rb - lib/omniauth/strategies/facebook.rb - omniauth-facebook.gemspec - test/fixtures/payload.json - test/fixtures/signed_request.txt - test/helper.rb - test/signed_request_test.rb - test/strategy_test.rb - test/support/shared_examples.rb homepage: https://github.com/mkdynamic/omniauth-facebook licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.0.14 signing_key: specification_version: 4 summary: Facebook OAuth2 Strategy for OmniAuth test_files: - test/fixtures/payload.json - test/fixtures/signed_request.txt - test/helper.rb - test/signed_request_test.rb - test/strategy_test.rb - test/support/shared_examples.rb omniauth-facebook-3.0.0/test/0000755000004100000410000000000012624164072016120 5ustar www-datawww-dataomniauth-facebook-3.0.0/test/signed_request_test.rb0000644000004100000410000000133412624164072022526 0ustar www-datawww-datarequire 'helper' require 'omniauth/facebook/signed_request' class SignedRequestTest < Minitest::Test def setup @value = fixture('signed_request.txt').strip @secret = "897z956a2z7zzzzz5783z458zz3z7556" @expected_payload = MultiJson.decode(fixture('payload.json')) end def test_signed_request_payload signed_request = OmniAuth::Facebook::SignedRequest.new(@value, @secret) assert_equal @expected_payload, signed_request.payload end def test_signed_request_parse payload = OmniAuth::Facebook::SignedRequest.parse(@value, @secret) assert_equal @expected_payload, payload end private def fixture(name) File.read(File.expand_path("fixtures/#{name}", File.dirname(__FILE__))) end end omniauth-facebook-3.0.0/test/helper.rb0000644000004100000410000000274112624164072017730 0ustar www-datawww-datarequire 'bundler/setup' require 'minitest/autorun' require 'mocha/setup' require 'omniauth/strategies/facebook' OmniAuth.config.test_mode = true module BlockTestHelper def test(name, &blk) method_name = "test_#{name.gsub(/\s+/, '_')}" raise "Method already defined: #{method_name}" if instance_methods.include?(method_name.to_sym) define_method method_name, &blk end end module CustomAssertions def assert_has_key(key, hash, msg = nil) msg = message(msg) { "Expected #{hash.inspect} to have key #{key.inspect}" } assert hash.has_key?(key), msg end def refute_has_key(key, hash, msg = nil) msg = message(msg) { "Expected #{hash.inspect} not to have key #{key.inspect}" } refute hash.has_key?(key), msg end end class TestCase < Minitest::Test extend BlockTestHelper include CustomAssertions end class StrategyTestCase < TestCase def setup @request = stub('Request') @request.stubs(:params).returns({}) @request.stubs(:cookies).returns({}) @request.stubs(:env).returns({}) @request.stubs(:scheme).returns({}) @request.stubs(:ssl?).returns(false) @client_id = '123' @client_secret = '53cr3tz' end def strategy @strategy ||= begin args = [@client_id, @client_secret, @options].compact OmniAuth::Strategies::Facebook.new(nil, *args).tap do |strategy| strategy.stubs(:request).returns(@request) end end end end Dir[File.expand_path('../support/**/*', __FILE__)].each &method(:require) omniauth-facebook-3.0.0/test/fixtures/0000755000004100000410000000000012624164072017771 5ustar www-datawww-dataomniauth-facebook-3.0.0/test/fixtures/payload.json0000644000004100000410000000052012624164072022312 0ustar www-datawww-data{ "algorithm": "HMAC-SHA256", "expires": 1308988800, "issued_at": 1308985018, "oauth_token": "111111111111111|2.AQBAttRlLVnwqNPZ.3600.1111111111.1-111111111111111|T49w3BqoZUegypru51Gra70hED8", "user": { "country": "de", "locale": "en_US", "age": { "min": 21 } }, "user_id": "111111111111111" } omniauth-facebook-3.0.0/test/fixtures/signed_request.txt0000644000004100000410000000062512624164072023556 0ustar www-datawww-data53umfudisP7mKhsi9nZboBg15yMZKhfQAARL9UoZtSE.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTExMTExMTExMTExMTF8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTExMTExMTExMS4xLTExMTExMTExMTExMTExMXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjExMTExMTExMTExMTExMSJ9 omniauth-facebook-3.0.0/test/strategy_test.rb0000644000004100000410000004212612624164072021353 0ustar www-datawww-datarequire 'helper' require 'omniauth-facebook' require 'openssl' require 'base64' class StrategyTest < StrategyTestCase include OAuth2StrategyTests end class ClientTest < StrategyTestCase test 'has correct Facebook site' do assert_equal 'https://graph.facebook.com', strategy.client.site end test 'has correct authorize url' do assert_equal 'https://www.facebook.com/dialog/oauth', strategy.client.options[:authorize_url] end test 'has correct token url with versioning' do @options = {:client_options => {:site => 'https://graph.facebook.net/v2.2'}} assert_equal 'oauth/access_token', strategy.client.options[:token_url] assert_equal 'https://graph.facebook.net/v2.2/oauth/access_token', strategy.client.token_url end end class CallbackUrlTest < StrategyTestCase test "returns the default callback url (omitting querystring)" do url_base = 'http://auth.request.com' @request.stubs(:url).returns("#{url_base}/some/page") strategy.stubs(:script_name).returns('') # as not to depend on Rack env strategy.stubs(:query_string).returns('?foo=bar') assert_equal "#{url_base}/auth/facebook/callback", strategy.callback_url end test "returns path from callback_path option (omitting querystring)" do @options = { :callback_path => "/auth/FB/done"} url_base = 'http://auth.request.com' @request.stubs(:url).returns("#{url_base}/page/path") strategy.stubs(:script_name).returns('') # as not to depend on Rack env strategy.stubs(:query_string).returns('?foo=bar') assert_equal "#{url_base}/auth/FB/done", strategy.callback_url end test "returns url from callback_url option" do url = 'https://auth.myapp.com/auth/fb/callback' @options = { :callback_url => url } assert_equal url, strategy.callback_url end end class AuthorizeParamsTest < StrategyTestCase test 'includes default scope for email' do assert strategy.authorize_params.is_a?(Hash) assert_equal 'email', strategy.authorize_params[:scope] end test 'includes display parameter from request when present' do @request.stubs(:params).returns({ 'display' => 'touch' }) assert strategy.authorize_params.is_a?(Hash) assert_equal 'touch', strategy.authorize_params[:display] end test 'includes auth_type parameter from request when present' do @request.stubs(:params).returns({ 'auth_type' => 'reauthenticate' }) assert strategy.authorize_params.is_a?(Hash) assert_equal 'reauthenticate', strategy.authorize_params[:auth_type] end test 'overrides default scope with parameter passed from request' do @request.stubs(:params).returns({ 'scope' => 'email' }) assert strategy.authorize_params.is_a?(Hash) assert_equal 'email', strategy.authorize_params[:scope] end end class TokeParamsTest < StrategyTestCase test 'has correct parse strategy' do assert_equal :query, strategy.token_params[:parse] end end class AccessTokenOptionsTest < StrategyTestCase test 'has correct param name by default' do assert_equal 'access_token', strategy.access_token_options[:param_name] end test 'has correct header format by default' do assert_equal 'OAuth %s', strategy.access_token_options[:header_format] end end class UidTest < StrategyTestCase def setup super strategy.stubs(:raw_info).returns({ 'id' => '123' }) end test 'returns the id from raw_info' do assert_equal '123', strategy.uid end end class InfoTest < StrategyTestCase test 'returns the secure facebook avatar url when `secure_image_url` option is specified' do @options = { :secure_image_url => true } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) assert_equal 'https://graph.facebook.com/321/picture', strategy.info['image'] end test 'returns the image_url based of the client site' do @options = { :secure_image_url => true, :client_options => {:site => "https://blah.facebook.com/v2.2"}} raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) assert_equal 'https://blah.facebook.com/v2.2/321/picture', strategy.info['image'] end test 'returns the image with size specified in the `image_size` option' do @options = { :image_size => 'normal' } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image'] end test 'returns the image with size specified as a symbol in the `image_size` option' do @options = { :image_size => :normal } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image'] end test 'returns the image with width and height specified in the `image_size` option' do @options = { :image_size => { :width => 123, :height => 987 } } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) assert_match 'width=123', strategy.info['image'] assert_match 'height=987', strategy.info['image'] assert_match 'http://graph.facebook.com/321/picture?', strategy.info['image'] end end class InfoTestOptionalDataPresent < StrategyTestCase def setup super @raw_info ||= { 'name' => 'Fred Smith' } strategy.stubs(:raw_info).returns(@raw_info) end test 'returns the name' do assert_equal 'Fred Smith', strategy.info['name'] end test 'returns the email' do @raw_info['email'] = 'fred@smith.com' assert_equal 'fred@smith.com', strategy.info['email'] end test 'returns the username as nickname' do @raw_info['username'] = 'fredsmith' assert_equal 'fredsmith', strategy.info['nickname'] end test 'returns the first name' do @raw_info['first_name'] = 'Fred' assert_equal 'Fred', strategy.info['first_name'] end test 'returns the last name' do @raw_info['last_name'] = 'Smith' assert_equal 'Smith', strategy.info['last_name'] end test 'returns the location name as location' do @raw_info['location'] = { 'id' => '104022926303756', 'name' => 'Palo Alto, California' } assert_equal 'Palo Alto, California', strategy.info['location'] end test 'returns bio as description' do @raw_info['bio'] = 'I am great' assert_equal 'I am great', strategy.info['description'] end test 'returns the facebook avatar url' do @raw_info['id'] = '321' assert_equal 'http://graph.facebook.com/321/picture', strategy.info['image'] end test 'returns the Facebook link as the Facebook url' do @raw_info['link'] = 'http://www.facebook.com/fredsmith' assert_kind_of Hash, strategy.info['urls'] assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook'] end test 'returns website url' do @raw_info['website'] = 'https://my-wonderful-site.com' assert_kind_of Hash, strategy.info['urls'] assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website'] end test 'return both Facebook link and website urls' do @raw_info['link'] = 'http://www.facebook.com/fredsmith' @raw_info['website'] = 'https://my-wonderful-site.com' assert_kind_of Hash, strategy.info['urls'] assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook'] assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website'] end test 'returns the positive verified status' do @raw_info['verified'] = true assert strategy.info['verified'] end test 'returns the negative verified status' do @raw_info['verified'] = false refute strategy.info['verified'] end end class InfoTestOptionalDataNotPresent < StrategyTestCase def setup super @raw_info ||= { 'name' => 'Fred Smith' } strategy.stubs(:raw_info).returns(@raw_info) end test 'has no email key' do refute_has_key 'email', strategy.info end test 'has no nickname key' do refute_has_key 'nickname', strategy.info end test 'has no first name key' do refute_has_key 'first_name', strategy.info end test 'has no last name key' do refute_has_key 'last_name', strategy.info end test 'has no location key' do refute_has_key 'location', strategy.info end test 'has no description key' do refute_has_key 'description', strategy.info end test 'has no urls' do refute_has_key 'urls', strategy.info end test 'has no verified key' do refute_has_key 'verified', strategy.info end end class RawInfoTest < StrategyTestCase def setup super @access_token = stub('OAuth2::AccessToken') @appsecret_proof = 'appsecret_proof' @options = {:appsecret_proof => @appsecret_proof, :fields => 'name,email'} end test 'performs a GET to https://graph.facebook.com/me' do strategy.stubs(:appsecret_proof).returns(@appsecret_proof) strategy.stubs(:access_token).returns(@access_token) params = {:params => @options} @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response')) strategy.raw_info end test 'performs a GET to https://graph.facebook.com/me with locale' do @options.merge!({ :locale => 'cs_CZ' }) strategy.stubs(:access_token).returns(@access_token) strategy.stubs(:appsecret_proof).returns(@appsecret_proof) params = {:params => @options} @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response')) strategy.raw_info end test 'performs a GET to https://graph.facebook.com/me with info_fields' do @options.merge!({:info_fields => 'about'}) strategy.stubs(:access_token).returns(@access_token) strategy.stubs(:appsecret_proof).returns(@appsecret_proof) params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'about'}} @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response')) strategy.raw_info end test 'performs a GET to https://graph.facebook.com/me with default info_fields' do strategy.stubs(:access_token).returns(@access_token) strategy.stubs(:appsecret_proof).returns(@appsecret_proof) params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'name,email'}} @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response')) strategy.raw_info end test 'returns a Hash' do strategy.stubs(:access_token).returns(@access_token) strategy.stubs(:appsecret_proof).returns(@appsecret_proof) raw_response = stub('Faraday::Response') raw_response.stubs(:body).returns('{ "ohai": "thar" }') raw_response.stubs(:status).returns(200) raw_response.stubs(:headers).returns({'Content-Type' => 'application/json' }) oauth2_response = OAuth2::Response.new(raw_response) params = {:params => @options} @access_token.stubs(:get).with('me', params).returns(oauth2_response) assert_kind_of Hash, strategy.raw_info assert_equal 'thar', strategy.raw_info['ohai'] end test 'returns an empty hash when the response is false' do strategy.stubs(:access_token).returns(@access_token) strategy.stubs(:appsecret_proof).returns(@appsecret_proof) oauth2_response = stub('OAuth2::Response', :parsed => false) params = {:params => @options} @access_token.stubs(:get).with('me', params).returns(oauth2_response) assert_kind_of Hash, strategy.raw_info assert_equal({}, strategy.raw_info) end test 'should not include raw_info in extras hash when skip_info is specified' do @options = { :skip_info => true } strategy.stubs(:raw_info).returns({:foo => 'bar' }) refute_has_key 'raw_info', strategy.extra end end class CredentialsTest < StrategyTestCase def setup super @access_token = stub('OAuth2::AccessToken') @access_token.stubs(:token) @access_token.stubs(:expires?) @access_token.stubs(:expires_at) @access_token.stubs(:refresh_token) strategy.stubs(:access_token).returns(@access_token) end test 'returns a Hash' do assert_kind_of Hash, strategy.credentials end test 'returns the token' do @access_token.stubs(:token).returns('123') assert_equal '123', strategy.credentials['token'] end test 'returns the expiry status' do @access_token.stubs(:expires?).returns(true) assert strategy.credentials['expires'] @access_token.stubs(:expires?).returns(false) refute strategy.credentials['expires'] end test 'returns the refresh token and expiry time when expiring' do ten_mins_from_now = (Time.now + 600).to_i @access_token.stubs(:expires?).returns(true) @access_token.stubs(:refresh_token).returns('321') @access_token.stubs(:expires_at).returns(ten_mins_from_now) assert_equal '321', strategy.credentials['refresh_token'] assert_equal ten_mins_from_now, strategy.credentials['expires_at'] end test 'does not return the refresh token when test is nil and expiring' do @access_token.stubs(:expires?).returns(true) @access_token.stubs(:refresh_token).returns(nil) assert_nil strategy.credentials['refresh_token'] refute_has_key 'refresh_token', strategy.credentials end test 'does not return the refresh token when not expiring' do @access_token.stubs(:expires?).returns(false) @access_token.stubs(:refresh_token).returns('XXX') assert_nil strategy.credentials['refresh_token'] refute_has_key 'refresh_token', strategy.credentials end end class ExtraTest < StrategyTestCase def setup super @raw_info = { 'name' => 'Fred Smith' } strategy.stubs(:raw_info).returns(@raw_info) end test 'returns a Hash' do assert_kind_of Hash, strategy.extra end test 'contains raw info' do assert_equal({ 'raw_info' => @raw_info }, strategy.extra) end end module SignedRequestHelpers def signed_request(payload, secret) encoded_payload = base64_encode_url(MultiJson.encode(payload)) encoded_signature = base64_encode_url(signature(encoded_payload, secret)) [encoded_signature, encoded_payload].join('.') end def base64_encode_url(value) Base64.encode64(value).tr('+/', '-_').gsub(/\n/, '') end def signature(payload, secret, algorithm = OpenSSL::Digest::SHA256.new) OpenSSL::HMAC.digest(algorithm, secret, payload) end end module SignedRequestTests class TestCase < StrategyTestCase include SignedRequestHelpers end class CookieAndParamNotPresentTest < TestCase test 'is nil' do assert_nil strategy.send(:signed_request_from_cookie) end test 'throws an error on calling build_access_token' do assert_raises(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError) { strategy.send(:with_authorization_code!) {} } end end class CookiePresentTest < TestCase def setup(algo = nil) super() @payload = { 'algorithm' => algo || 'HMAC-SHA256', 'code' => 'm4c0d3z', 'issued_at' => Time.now.to_i, 'user_id' => '123456' } @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)}) end test 'parses the access code out from the cookie' do assert_equal @payload, strategy.send(:signed_request_from_cookie) end test 'throws an error if the algorithm is unknown' do setup('UNKNOWN-ALGO') assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message end end class EmptySignedRequestTest < TestCase def setup super @request.stubs(:params).returns({'signed_request' => ''}) end test 'empty param' do assert_equal nil, strategy.send(:signed_request_from_cookie) end end class MissingCodeInParamsRequestTest < TestCase def setup super @request.stubs(:params).returns({}) end test 'calls fail! when a code is not included in the params' do strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError)) strategy.callback_phase end end class MissingCodeInCookieRequestTest < TestCase def setup(algo = nil) super() @payload = { 'algorithm' => algo || 'HMAC-SHA256', 'code' => nil, 'issued_at' => Time.now.to_i, 'user_id' => '123456' } @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)}) end test 'calls fail! when a code is not included in the cookie' do strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError)) strategy.callback_phase end end class UnknownAlgorithmInCookieRequestTest < TestCase def setup super() @payload = { 'algorithm' => 'UNKNOWN-ALGO', 'code' => nil, 'issued_at' => Time.now.to_i, 'user_id' => '123456' } @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)}) end test 'calls fail! when an algorithm is unknown' do strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError)) strategy.callback_phase end end end omniauth-facebook-3.0.0/test/support/0000755000004100000410000000000012624164072017634 5ustar www-datawww-dataomniauth-facebook-3.0.0/test/support/shared_examples.rb0000644000004100000410000000645212624164072023334 0ustar www-datawww-data# NOTE it would be useful if this lived in omniauth-oauth2 eventually module OAuth2StrategyTests def self.included(base) base.class_eval do include ClientTests include AuthorizeParamsTests include CSRFAuthorizeParamsTests include TokenParamsTests end end module ClientTests extend BlockTestHelper test 'should be initialized with symbolized client_options' do @options = { :client_options => { 'authorize_url' => 'https://example.com' } } assert_equal 'https://example.com', strategy.client.options[:authorize_url] end end module AuthorizeParamsTests extend BlockTestHelper test 'should include any authorize params passed in the :authorize_params option' do @options = { :authorize_params => { :foo => 'bar', :baz => 'zip' } } assert_equal 'bar', strategy.authorize_params['foo'] assert_equal 'zip', strategy.authorize_params['baz'] end test 'should include top-level options that are marked as :authorize_options' do @options = { :authorize_options => [:scope, :foo], :scope => 'bar', :foo => 'baz' } assert_equal 'bar', strategy.authorize_params['scope'] assert_equal 'baz', strategy.authorize_params['foo'] end test 'should exclude top-level options that are not passed' do @options = { :authorize_options => [:bar] } refute_has_key :bar, strategy.authorize_params refute_has_key 'bar', strategy.authorize_params end end module CSRFAuthorizeParamsTests extend BlockTestHelper test 'should store random state in the session when none is present in authorize or request params' do assert_includes strategy.authorize_params.keys, 'state' refute_empty strategy.authorize_params['state'] refute_empty strategy.session['omniauth.state'] assert_equal strategy.authorize_params['state'], strategy.session['omniauth.state'] end test 'should not store state in the session when present in authorize params vs. a random one' do @options = { :authorize_params => { :state => 'bar' } } refute_empty strategy.authorize_params['state'] refute_equal 'bar', strategy.authorize_params[:state] refute_empty strategy.session['omniauth.state'] refute_equal 'bar', strategy.session['omniauth.state'] end test 'should not store state in the session when present in request params vs. a random one' do @request.stubs(:params).returns({ 'state' => 'foo' }) refute_empty strategy.authorize_params['state'] refute_equal 'foo', strategy.authorize_params[:state] refute_empty strategy.session['omniauth.state'] refute_equal 'foo', strategy.session['omniauth.state'] end end module TokenParamsTests extend BlockTestHelper test 'should include any authorize params passed in the :token_params option' do @options = { :token_params => { :foo => 'bar', :baz => 'zip' } } assert_equal 'bar', strategy.token_params['foo'] assert_equal 'zip', strategy.token_params['baz'] end test 'should include top-level options that are marked as :token_options' do @options = { :token_options => [:scope, :foo], :scope => 'bar', :foo => 'baz' } assert_equal 'bar', strategy.token_params['scope'] assert_equal 'baz', strategy.token_params['foo'] end end end omniauth-facebook-3.0.0/omniauth-facebook.gemspec0000644000004100000410000000156012624164072022103 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path('../lib', __FILE__) require 'omniauth/facebook/version' Gem::Specification.new do |s| s.name = 'omniauth-facebook' s.version = OmniAuth::Facebook::VERSION s.authors = ['Mark Dodwell', 'Josef Šimánek'] s.email = ['mark@madeofcode.com', 'retro@ballgag.cz'] s.summary = 'Facebook OAuth2 Strategy for OmniAuth' s.homepage = 'https://github.com/mkdynamic/omniauth-facebook' s.license = 'MIT' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } s.require_paths = ['lib'] s.add_runtime_dependency 'omniauth-oauth2', '~> 1.2' s.add_development_dependency 'minitest' s.add_development_dependency 'mocha' s.add_development_dependency 'rake' end omniauth-facebook-3.0.0/.gitignore0000644000004100000410000000011112624164072017122 0ustar www-datawww-data*.gem .bundle .rspec /Gemfile.lock pkg/* .powenv tmp bin example/app.log omniauth-facebook-3.0.0/example/0000755000004100000410000000000012624164072016574 5ustar www-datawww-dataomniauth-facebook-3.0.0/example/Gemfile.lock0000644000004100000410000000220612624164072021016 0ustar www-datawww-dataPATH remote: ../ specs: omniauth-facebook (2.0.0) omniauth-oauth2 (~> 1.2) GEM remote: https://rubygems.org/ specs: backports (3.3.5) faraday (0.9.0) multipart-post (>= 1.2, < 3) hashie (3.2.0) jwt (1.0.0) multi_json (1.8.2) multi_xml (0.5.5) multipart-post (2.0.0) oauth2 (1.0.0) faraday (>= 0.8, < 0.10) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (~> 1.2) omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) omniauth-oauth2 (1.2.0) faraday (>= 0.8, < 0.10) multi_json (~> 1.3) oauth2 (~> 1.0) omniauth (~> 1.2) rack (1.5.2) rack-protection (1.5.1) rack rack-test (0.6.2) rack (>= 1.0) sinatra (1.4.4) rack (~> 1.4) rack-protection (~> 1.4) tilt (~> 1.3, >= 1.3.4) sinatra-contrib (1.4.2) backports (>= 2.0) multi_json rack-protection rack-test sinatra (~> 1.4.0) tilt (~> 1.3) sinatra-reloader (1.0) sinatra-contrib tilt (1.4.1) PLATFORMS ruby DEPENDENCIES omniauth-facebook! sinatra sinatra-reloader omniauth-facebook-3.0.0/example/Gemfile0000644000004100000410000000015412624164072020067 0ustar www-datawww-datasource 'https://rubygems.org' gem 'sinatra' gem 'sinatra-reloader' gem 'omniauth-facebook', :path => '../' omniauth-facebook-3.0.0/example/app.rb0000644000004100000410000000547712624164072017716 0ustar www-datawww-datarequire 'sinatra' require "sinatra/reloader" require 'yaml' # configure sinatra set :run, false set :raise_errors, true # setup logging to file log = File.new("app.log", "a+") $stdout.reopen(log) $stderr.reopen(log) $stderr.sync = true $stdout.sync = true # server-side flow get '/server-side' do # NOTE: You would just hit this endpoint directly from the browser in a real app. The redirect is just here to # explicit declare this server-side flow. redirect '/auth/facebook' end # client-side flow get '/client-side' do content_type 'text/html' # NOTE: When you enable cookie below in the FB.init call the GET request in the FB.login callback will send a signed # request in a cookie back the OmniAuth callback which will parse out the authorization code and obtain an # access_token with it. <<-END Client-side Flow Example

Connect to FB!

END end get '/auth/:provider/callback' do content_type 'application/json' MultiJson.encode(request.env) end get '/auth/failure' do content_type 'application/json' MultiJson.encode(request.env) end omniauth-facebook-3.0.0/example/config.ru0000644000004100000410000000040512624164072020410 0ustar www-datawww-datarequire 'bundler/setup' require 'omniauth-facebook' require './app.rb' use Rack::Session::Cookie, :secret => 'abc123' use OmniAuth::Builder do provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => 'email,read_stream' end run Sinatra::Application omniauth-facebook-3.0.0/CHANGELOG.md0000644000004100000410000000723312624164072016757 0ustar www-datawww-data## 3.0.0 (2015-10-26) Changes: - Remove query string from redirect_uri on callback by default (#221, @gioblu) - Signed request parsing extracted to `OmniAuth::Facebook::SignedRequest` class. (#183, @simi, @Vrael) - Change default value of `info_fields` to `name,email` for the [graph-api-v2.4](https://developers.facebook.com/blog/post/2015/07/08/graph-api-v2.4/). ([#209](https://github.com/mkdynamic/omniauth-facebook/pull/209)) ## 2.0.1 (2015-02-21) Bugfixes: - Allow versioning by not forcing absolute path for graph requests (#180, @frausto) - Allow the image_size option to be set as a symbol. (#182, @jgrau) ## 2.0.0 (2014-08-07) Changes: - remove support for canvas app flow (765ed9, @mkdynamic) Bugfixes: - bump omniauth-oauth2 dependency which addresses CVE-2012-6134 (#162, @linedotstar) - rescue `NoAuthorizationCodeError` in callback_phase (a0036b, @tomoya55) - fix CSRF exception when using FB JS SDK and parsing signed request (765ed9, @mkdynamic) ## 1.6.0 (2014-01-13) Features: - ability to specify `auth_type` per-request (#78, @sebastian-stylesaint) - image dimension can be set using `image_size` option (#91, @weilu) - update Facebook authorize URL to fix broken authorization (#103, @dlackty) - adds `info_fields` option (#109, @bloudermilk) - adds `locale` parameter (#133, @donbobka, @simi) - add automatically `appsecret_proof` (#140, @nlsrchtr, @simi) Changes: - `NoAuthorizationCodeError` and `UnknownSignatureAlgorithmError` will now `fail!` (#117, @nchelluri) - don't try to parse the signature if it's nil (#127, @oriolgual) ## 1.5.1 (2013-11-18) Changes: - don't use `access_token` in URL [CVE-2013-4593](https://github.com/mkdynamic/omniauth-facebook/wiki/Access-token-vulnerability:-CVE-2013-4593) (@homakov, @mkdynamic, @simi) ## 1.5.0 (2013-11-13) Changes: - remove `state` param to fix CSRF vulnerabilty [CVE-2013-4562](https://github.com/mkdynamic/omniauth-facebook/wiki/CSRF-vulnerability:-CVE-2013-4562) (@homakov, @mkdynamic, @simi) ## 1.4.1 (2012-07-07) Changes: - update to omniauth-oauth2 1.1.0 for csrf protection (@mkdynamic) ## 1.4.0 (2012-06-24) Features: - obey `skip_info?` config (@mkdynamic) - add support of the `:auth_type` option to `:authorize_options` (#58, @JHeidinga, @mkdynamic) - support `access_token` parameter as part of the callback request (#62, @steverandy) ## 1.3.0 (2012-05-05) Features: - dynamic permissions in the auth params (#30, @famoseagle) - add support for facebook canvas (@mkdynamic) - add verified key to the info hash (#34, @ryansobol) - add option to use secure url for image in auth hash (@mkdynamic) - add option to specify image size (@mkdynamic) Changes: - have `raw_info` return an empty hash if the Facebook response returns false (#44, @brianjlandau) - prevent oauth2 from interpreting Facebook's expires field as `expires_in`, when it's really `expires_at` (#39, @watsonbox) - remove deprecated `offline_access` permission (@mkdynamic) - tidy up the `callback_url` option (@mkdynamic) ## 1.2.0 (2012-01-06) Features: - add `state` to authorization params (#19, @GermanDZ) Changes: - lock to `rack ~> 1.3.6` (@mkdynamic) ## 1.1.0 (2011-12-10) Features: - add `callback_url` option (#13, @gumayunov) - support for parsing code from signed request cookie (client-side flow) (@mkdynamic) ## 1.0.0 (2011-11-19) Features: - allow passing of display via option (@mkdynamic) Bugfixes: - fix `ten_mins_from_now` calculation (#7, @olegkovalenko) ## 1.0.0.rc2 (2011-11-11) Features: - allow passing `display` parameter (@mkdynamic) - included default scope (@mkdynamic) ## 1.0.0.rc1 (2011-10-29) - first public gem release (@mkdynamic) omniauth-facebook-3.0.0/README.md0000644000004100000410000002254012624164072016423 0ustar www-datawww-data**IMPORTANT: If you're running < 1.5.1, please upgrade to the latest version to address 3 security vulnerabilities. More details [here](https://github.com/mkdynamic/omniauth-facebook/wiki/CSRF-vulnerability:-CVE-2013-4562), [here](https://github.com/mkdynamic/omniauth-facebook/wiki/Access-token-vulnerability:-CVE-2013-4593) and [here](http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2012-6134).** --- # OmniAuth Facebook  [![Build Status](https://secure.travis-ci.org/mkdynamic/omniauth-facebook.svg?branch=master)](https://travis-ci.org/mkdynamic/omniauth-facebook) [![Gem Version](https://img.shields.io/gem/v/omniauth-facebook.svg)](https://rubygems.org/gems/omniauth-facebook) **These notes are based on master, please see tags for README pertaining to specific releases.** Facebook OAuth2 Strategy for OmniAuth. Supports the OAuth 2.0 server-side and client-side flows. Read the Facebook docs for more details: http://developers.facebook.com/docs/authentication ## Installing Add to your `Gemfile`: ```ruby gem 'omniauth-facebook' ``` Then `bundle install`. ## Usage `OmniAuth::Strategies::Facebook` is simply a Rack middleware. Read the OmniAuth docs for detailed instructions: https://github.com/intridea/omniauth. Here's a quick example, adding the middleware to a Rails app in `config/initializers/omniauth.rb`: ```ruby Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'] end ``` [See the example Sinatra app for full examples](https://github.com/mkdynamic/omniauth-facebook/blob/master/example/config.ru) of both the server and client-side flows (including using the Facebook Javascript SDK). ## Configuring You can configure several options, which you pass in to the `provider` method via a `Hash`: Option name | Default | Explanation --- | --- | --- `scope` | `email` | A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions: https://developers.facebook.com/docs/reference/login/ `display` | `page` | The display context to show the authentication page. Options are: `page`, `popup` and `touch`. Read the Facebook docs for more details: https://developers.facebook.com/docs/reference/dialogs/oauth/ `image_size` | `square` | Set the size for the returned image url in the auth hash. Valid options include `square` (50x50), `small` (50 pixels wide, variable height), `normal` (100 pixels wide, variable height), or `large` (about 200 pixels wide, variable height). Additionally, you can request a picture of a specific size by setting this option to a hash with `:width` and `:height` as keys. This will return an available profile picture closest to the requested size and requested aspect ratio. If only `:width` or `:height` is specified, we will return a picture whose width or height is closest to the requested size, respectively. `info_fields` | 'name,email' | Specify exactly which fields should be returned when getting the user's info. Value should be a comma-separated string as per https://developers.facebook.com/docs/graph-api/reference/user/ (only `/me` endpoint). `locale` | | Specify locale which should be used when getting the user's info. Value should be locale string as per https://developers.facebook.com/docs/reference/api/locale/. `auth_type` | | Optionally specifies the requested authentication features as a comma-separated list, as per https://developers.facebook.com/docs/facebook-login/reauthentication/. Valid values are `https` (checks for the presence of the secure cookie and asks for re-authentication if it is not present), and `reauthenticate` (asks the user to re-authenticate unconditionally). Use 'rerequest' when you want to request premissions. Default is `nil`. `secure_image_url` | `false` | Set to `true` to use https for the avatar image url returned in the auth hash. `callback_url` / `callback_path` | | Specify a custom callback URL used during the server-side flow. Note this must be allowed by your app configuration on Facebook (see 'Valid OAuth redirect URIs' under the 'Advanced' settings section in the configuration for your Facebook app for more details). For example, to request `email`, `user_birthday` and `read_stream` permissions and display the authentication page in a popup window: ```ruby Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], :scope => 'email,user_birthday,read_stream', :display => 'popup' end ``` ### API Version OmniAuth Facebook uses unversioned API endpoints by default. You can configure custom endpoints via `client_options` hash passed to `provider`. ```ruby use OmniAuth::Builder do provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :client_options => { :site => 'https://graph.facebook.com/v2.0', :authorize_url => "https://www.facebook.com/v2.0/dialog/oauth" } end ``` ### Per-Request Options If you want to set the `display` format, `auth_type`, or `scope` on a per-request basis, you can just pass it to the OmniAuth request phase URL, for example: `/auth/facebook?display=popup` or `/auth/facebook?scope=email`. ## Auth Hash Here's an example *Auth Hash* available in `request.env['omniauth.auth']`: ```ruby { :provider => 'facebook', :uid => '1234567', :info => { :nickname => 'jbloggs', :email => 'joe@bloggs.com', :name => 'Joe Bloggs', :first_name => 'Joe', :last_name => 'Bloggs', :image => 'http://graph.facebook.com/1234567/picture?type=square', :urls => { :Facebook => 'http://www.facebook.com/jbloggs' }, :location => 'Palo Alto, California', :verified => true }, :credentials => { :token => 'ABCDEF...', # OAuth 2.0 access_token, which you may wish to store :expires_at => 1321747205, # when the access token expires (it always will) :expires => true # this will always be true }, :extra => { :raw_info => { :id => '1234567', :name => 'Joe Bloggs', :first_name => 'Joe', :last_name => 'Bloggs', :link => 'http://www.facebook.com/jbloggs', :username => 'jbloggs', :location => { :id => '123456789', :name => 'Palo Alto, California' }, :gender => 'male', :email => 'joe@bloggs.com', :timezone => -8, :locale => 'en_US', :verified => true, :updated_time => '2011-11-11T06:21:03+0000' } } } ``` The precise information available may depend on the permissions which you request. ## Client-side Flow with Facebook Javascript SDK You can use the Facebook Javascript SDK with `FB.login`, and just hit the callback endpoint (`/auth/facebook/callback` by default) once the user has authenticated in the success callback. **Note that you must enable cookies in the `FB.init` config for this process to work.** See the example Sinatra app under `example/` and read the [Facebook docs on Login for JavaScript](https://developers.facebook.com/docs/facebook-login/login-flow-for-web/) for more details. ### How it Works The client-side flow is supported by parsing the authorization code from the signed request which Facebook places in a cookie. When you call `/auth/facebook/callback` in the success callback of `FB.login` that will pass the cookie back to the server. omniauth-facebook will see this cookie and: 1. parse it, 2. extract the authorization code contained in it 3. and hit Facebook and obtain an access token which will get placed in the `request.env['omniauth.auth']['credentials']` hash. ## Token Expiry The expiration time of the access token you obtain will depend on which flow you are using. ### Client-Side Flow If you use the client-side flow, Facebook will give you back a short lived access token (~ 2 hours). You can exchange this short lived access token for a longer lived version. Read the [Facebook docs](https://developers.facebook.com/docs/facebook-login/access-tokens/) for more information on exchanging a short lived token for a long lived token. ### Server-Side Flow If you use the server-side flow, Facebook will give you back a longer lived access token (~ 60 days). ## Supported Rubies Actively tested with the following Ruby versions: - MRI 2.1.0 - MRI 2.0.0 - MRI 1.9.3 - MRI 1.9.2 - MRI 1.8.7 - JRuby 1.7.9 - Rubinius (latest stable) ## License Copyright (c) 2012 by Mark Dodwell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mkdynamic/omniauth-facebook/trend.png)](https://bitdeli.com/free "Bitdeli Badge")