omniauth-facebook-10.0.0/0000755000004100000410000000000014632135304015214 5ustar www-datawww-dataomniauth-facebook-10.0.0/.gitignore0000644000004100000410000000010114632135304017174 0ustar www-datawww-data*.gem .bundle .rspec /Gemfile.lock pkg/* .powenv .powder tmp bin omniauth-facebook-10.0.0/omniauth-facebook.gemspec0000644000004100000410000000163214632135304022156 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/simi/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', '< 3' s.add_runtime_dependency 'bigdecimal' s.add_development_dependency 'minitest' s.add_development_dependency 'mocha' s.add_development_dependency 'rake' end omniauth-facebook-10.0.0/example/0000755000004100000410000000000014632135304016647 5ustar www-datawww-dataomniauth-facebook-10.0.0/example/Gemfile.lock0000644000004100000410000000236314632135304021075 0ustar www-datawww-dataPATH remote: .. specs: omniauth-facebook (8.0.0) omniauth-oauth2 (~> 1.2) GEM remote: https://rubygems.org/ specs: backports (3.15.0) faraday (1.1.0) multipart-post (>= 1.2, < 3) ruby2_keywords hashie (4.1.0) jwt (2.2.2) multi_json (1.14.1) multi_xml (0.6.0) multipart-post (2.1.1) mustermann (1.1.1) ruby2_keywords (~> 0.0.1) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) omniauth-oauth2 (1.7.0) oauth2 (~> 1.4) omniauth (~> 1.9) rack (2.2.3) rack-protection (2.0.8.1) rack ruby2_keywords (0.0.2) sinatra (2.0.8.1) mustermann (~> 1.0) rack (~> 2.0) rack-protection (= 2.0.8.1) tilt (~> 2.0) sinatra-contrib (2.0.8.1) backports (>= 2.8.2) multi_json mustermann (~> 1.0) rack-protection (= 2.0.8.1) sinatra (= 2.0.8.1) tilt (~> 2.0) sinatra-reloader (1.0) sinatra-contrib tilt (2.0.10) PLATFORMS ruby x64-mingw32 DEPENDENCIES omniauth-facebook! sinatra sinatra-reloader BUNDLED WITH 1.17.3 omniauth-facebook-10.0.0/example/app.rb0000644000004100000410000000546314632135304017764 0ustar www-datawww-datarequire 'sinatra' require "sinatra/reloader" require 'yaml' require 'json' # configure sinatra set :run, false set :raise_errors, true # REQUEST STEP (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 # REQUEST STEP (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. <<-HTML Client-side Flow Example

Connect to FB!

HTML end # CALLBACK STEP # - redirected here for server-side flow # - ajax request made here for client-side flow get '/auth/:provider/callback' do content_type 'application/json' JSON.dump(request.env) end omniauth-facebook-10.0.0/example/Gemfile0000644000004100000410000000015114632135304020137 0ustar www-datawww-datasource 'https://rubygems.org' gem 'sinatra' gem 'sinatra-reloader' gem 'omniauth-facebook', path: '../' omniauth-facebook-10.0.0/example/config.ru0000644000004100000410000000036514632135304020470 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['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'] end run Sinatra::Application omniauth-facebook-10.0.0/.github/0000755000004100000410000000000014632135304016554 5ustar www-datawww-dataomniauth-facebook-10.0.0/.github/workflows/0000755000004100000410000000000014632135304020611 5ustar www-datawww-dataomniauth-facebook-10.0.0/.github/workflows/stale.yml0000644000004100000410000000153114632135304022444 0ustar www-datawww-dataname: Mark stale issues and pull requests on: schedule: - cron: "0 0 * * *" jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' stale-issue-label: 'no-issue-activity' stale-pr-label: 'no-pr-activity' days-before-stale: 30 days-before-close: 5 exempt-pr-label: 'pinned' exempt-issue-label: 'pinned' omniauth-facebook-10.0.0/.github/workflows/ci.yml0000644000004100000410000000075314632135304021734 0ustar www-datawww-dataname: Ruby on: [push, pull_request] jobs: test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: ruby: - "3.0" - "3.1" - "3.2" - "3.3" - head steps: - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true # 'bundle install' and cache - name: Run tests run: bundle exec rake omniauth-facebook-10.0.0/lib/0000755000004100000410000000000014632135304015762 5ustar www-datawww-dataomniauth-facebook-10.0.0/lib/omniauth-facebook.rb0000644000004100000410000000003414632135304021677 0ustar www-datawww-datarequire 'omniauth/facebook' omniauth-facebook-10.0.0/lib/omniauth/0000755000004100000410000000000014632135304017606 5ustar www-datawww-dataomniauth-facebook-10.0.0/lib/omniauth/facebook/0000755000004100000410000000000014632135304021357 5ustar www-datawww-dataomniauth-facebook-10.0.0/lib/omniauth/facebook/signed_request.rb0000644000004100000410000000253014632135304024725 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 = JSON.parse(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-10.0.0/lib/omniauth/facebook/version.rb0000644000004100000410000000010314632135304023363 0ustar www-datawww-datamodule OmniAuth module Facebook VERSION = '10.0.0' end end omniauth-facebook-10.0.0/lib/omniauth/facebook.rb0000644000004100000410000000011314632135304021677 0ustar www-datawww-datarequire 'omniauth/facebook/version' require 'omniauth/strategies/facebook' omniauth-facebook-10.0.0/lib/omniauth/strategies/0000755000004100000410000000000014632135304021760 5ustar www-datawww-dataomniauth-facebook-10.0.0/lib/omniauth/strategies/facebook.rb0000644000004100000410000001444514632135304024066 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' DEFAULT_FACEBOOK_API_VERSION = 'v19.0'.freeze option :client_options, { site: "https://graph.facebook.com/#{DEFAULT_FACEBOOK_API_VERSION}", authorize_url: "https://www.facebook.com/#{DEFAULT_FACEBOOK_API_VERSION}/dialog/oauth", token_url: 'oauth/access_token' } option :access_token_options, { header_format: 'OAuth %s', param_name: 'access_token' } option :authorization_code_from_signed_request_in_cookie, nil option :authorize_options, [:scope, :display, :auth_type, :config_id] option :secure_image_url, true 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 options.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 + 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+, +auth_type+ or +config_id+ 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 config_id].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 options.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') options.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 = { access_token: access_token.token } if options[:image_size].is_a?(String) || options[:image_size].is_a?(Symbol) query[:type] = options[:image_size] elsif options[:image_size].is_a?(Hash) query.merge!(options[:image_size]) end url.query = Rack::Utils.build_query(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-10.0.0/test/0000755000004100000410000000000014632135304016173 5ustar www-datawww-dataomniauth-facebook-10.0.0/test/helper.rb0000644000004100000410000000312114632135304017774 0ustar www-datawww-datarequire 'bundler/setup' require 'minitest/autorun' require 'mocha/minitest' 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' @options = {} @facebook_api_version = OmniAuth::Strategies::Facebook::DEFAULT_FACEBOOK_API_VERSION 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-10.0.0/test/fixtures/0000755000004100000410000000000014632135304020044 5ustar www-datawww-dataomniauth-facebook-10.0.0/test/fixtures/payload.json0000644000004100000410000000052014632135304022365 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-10.0.0/test/fixtures/signed_request.txt0000644000004100000410000000062514632135304023631 0ustar www-datawww-data53umfudisP7mKhsi9nZboBg15yMZKhfQAARL9UoZtSE.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTExMTExMTExMTExMTF8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTExMTExMTExMS4xLTExMTExMTExMTExMTExMXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjExMTExMTExMTExMTExMSJ9 omniauth-facebook-10.0.0/test/signed_request_test.rb0000644000004100000410000000132614632135304022602 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 = JSON.parse(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-10.0.0/test/strategy_test.rb0000644000004100000410000004625114632135304021431 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/#{@facebook_api_version}", strategy.client.site end test 'has correct authorize url' do assert_equal "https://www.facebook.com/#{@facebook_api_version}/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' script_name = '/script_name' @request.stubs(:url).returns("#{url_base}/some/page") strategy.stubs(:script_name).returns(script_name) # as not to depend on Rack env strategy.stubs(:query_string).returns('?foo=bar') assert_equal "#{url_base}#{script_name}/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 config_id parameter from request when present' do @request.stubs(:params).returns({ 'config_id' => '000111222' }) assert strategy.authorize_params.is_a?(Hash) assert_equal '000111222', strategy.authorize_params[:config_id] 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 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 def setup super @access_token = stub('OAuth2::AccessToken') @access_token.stubs(:token).returns('test_access_token') end test 'returns the secure facebook avatar url when `secure_image_url` option is set to true' do @options = { secure_image_url: true } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) strategy.stubs(:access_token).returns(@access_token) assert_equal "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token", strategy.info['image'] end test 'returns the non-ssl facebook avatar url when `secure_image_url` option is set to false' do @options = { secure_image_url: false } raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) strategy.stubs(:access_token).returns(@access_token) assert_equal "http://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token", strategy.info['image'] end test 'returns the secure facebook avatar url when `secure_image_url` option is omitted' do raw_info = { 'name' => 'Fred Smith', 'id' => '321' } strategy.stubs(:raw_info).returns(raw_info) strategy.stubs(:access_token).returns(@access_token) assert_equal "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token", 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) strategy.stubs(:access_token).returns(@access_token) assert_equal "https://blah.facebook.com/v2.2/321/picture?access_token=test_access_token", 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) strategy.stubs(:access_token).returns(@access_token) assert_equal "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token&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) strategy.stubs(:access_token).returns(@access_token) assert_equal "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token&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) strategy.stubs(:access_token).returns(@access_token) assert_match 'width=123', strategy.info['image'] assert_match 'height=987', strategy.info['image'] assert_match "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token", strategy.info['image'] end end class InfoTestOptionalDataPresent < StrategyTestCase def setup super @raw_info ||= { 'name' => 'Fred Smith' } strategy.stubs(:raw_info).returns(@raw_info) access_token = stub('OAuth2::AccessToken') access_token.stubs(:token).returns('test_access_token') strategy.stubs(:access_token).returns(access_token) 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 "https://graph.facebook.com/#{@facebook_api_version}/321/picture?access_token=test_access_token", 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) access_token = stub('OAuth2::AccessToken') access_token.stubs(:token).returns('test_access_token') strategy.stubs(:access_token).returns(access_token) 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/#{@facebook_api_version}/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/#{@facebook_api_version}/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/#{@facebook_api_version}/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/#{@facebook_api_version}/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(JSON.dump(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_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-10.0.0/test/support/0000755000004100000410000000000014632135304017707 5ustar www-datawww-dataomniauth-facebook-10.0.0/test/support/shared_examples.rb0000644000004100000410000000637214632135304023410 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-10.0.0/Rakefile0000644000004100000410000000026014632135304016657 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-10.0.0/Gemfile0000644000004100000410000000007514632135304016511 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rack', '>= 2.0' omniauth-facebook-10.0.0/README.md0000644000004100000410000002233614632135304016501 0ustar www-datawww-data# OmniAuth Facebook  [![Build Status](https://secure.travis-ci.org/simi/omniauth-facebook.svg?branch=master)](https://travis-ci.org/simi/omniauth-facebook) [![Gem Version](https://img.shields.io/gem/v/omniauth-facebook.svg)](https://rubygems.org/gems/omniauth-facebook) 📣 **NOTICE** We’re looking for maintainers to help keep this project up-to-date. If you are interested in helping please open an Issue expressing your interest. Thanks! 📣 **These notes are based on master, please see tags for README pertaining to specific releases.** Facebook OAuth2 Strategy for OmniAuth. Supports 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_APP_ID'], ENV['FACEBOOK_APP_SECRET'] end ``` [See the example Sinatra app for full examples](https://github.com/simi/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 `config_id` | | The configuration ID to use for a System User access token with Facebook Login for Business. Read the Facebook docs for more details: https://developers.facebook.com/docs/facebook-login/facebook-login-for-business#invoke-a--login-dialog `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` | `true` | Set to `true` to use https for the avatar image url returned in the auth hash. SSL is mandatory as per https://developers.facebook.com/docs/facebook-login/security#surfacearea. `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_APP_ID'], ENV['FACEBOOK_APP_SECRET'], scope: 'email,user_birthday,read_stream', display: 'popup' end ``` ### API Version OmniAuth Facebook uses versioned API endpoints by default (current v19.0). You can configure a different version via `client_options` hash passed to `provider`, specifically you should change the version in the `site` and `authorize_url` parameters. For example, to change to v20.0 (assuming that exists): ```ruby use OmniAuth::Builder do provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], client_options: { site: 'https://graph.facebook.com/v20.0', authorize_url: "https://www.facebook.com/v20.0/dialog/oauth" } end ``` ### Per-Request Options If you want to set the `display` format, `auth_type`, `scope` or `config_id` on a per-request basis, you can just pass it to the OmniAuth request phase URL, for example: `/auth/facebook?display=popup`, `/auth/facebook?scope=email` or `/auth/facebook?config_id=001`. ## Auth Hash Here's an example *Auth Hash* available in `request.env['omniauth.auth']`: ```ruby { provider: 'facebook', uid: '1234567', info: { email: 'joe@bloggs.com', name: 'Joe Bloggs', first_name: 'Joe', last_name: 'Bloggs', image: 'http://graph.facebook.com/1234567/picture?type=square&access_token=...', 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 - Ruby MRI (3.0, 3.1, 3.2 and 3.3) ## 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. omniauth-facebook-10.0.0/CHANGELOG.md0000644000004100000410000001106114632135304017024 0ustar www-datawww-data## 10.0.0 (2024-05-23) Changes: - bumped version of FB Graph API to v19.0 ## 9.0.0 (2021-10-25) Changes: - bumped version of FB Graph API to v5.0 ## 8.0.0 (2020-10-20) Changes: - user profile picture link includes access token (#344, @anklos) ## 7.0.0 (2020-08-03) Changes: - bumped version of FB Graph API to v4.0 ## 6.0.0 (2020-01-27) Changes: - bumped version of FB Graph API to v3.0 ## 5.0.0 (2018-03-29) Changes: - bumped version of FB Graph API to v2.10 (#297, @piotrjaworski) - use only CRuby 2.0+ on CI (#298, @simi) ## 4.0.0 (2016-07-26) Changes: - drop support for Ruby < 1.9.3 (@mkdynamic) - switch to versioned FB APIs, currently using v2.6 (#245, @printercu, @mkdynamic) - remove deprecated :nickname field from README example (#223, @abelorian) - add Ruby 2.2 + 2.3.0 to CI (#225, @tricknotes, @mkdynamic, @anoraak) - update example app (@mkdynamic) ## 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)