Full Code of omniauth/omniauth-oauth2 for AI

master 1481c33b3ffd cached
17 files
23.1 KB
6.6k tokens
21 symbols
1 requests
Download .txt
Repository: omniauth/omniauth-oauth2
Branch: master
Commit: 1481c33b3ffd
Files: 17
Total size: 23.1 KB

Directory structure:
gitextract_b905nxjk/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE.md
├── README.md
├── Rakefile
├── SECURITY.md
├── lib/
│   ├── omniauth/
│   │   └── strategies/
│   │       └── oauth2.rb
│   ├── omniauth-oauth2/
│   │   └── version.rb
│   └── omniauth-oauth2.rb
├── omniauth-oauth2.gemspec
└── spec/
    ├── helper.rb
    └── omniauth/
        └── strategies/
            └── oauth2_spec.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: bobbymcwho
tidelift: rubygems/omniauth-oauth2


================================================
FILE: .github/workflows/main.yml
================================================
name: Ruby

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  test:
    runs-on: ${{ matrix.os }}
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
        ruby: ['3.0', 3.1, 3.2, 3.3, 3.4, head, debug, truffleruby, truffleruby-head, jruby, jruby-head]
    steps:
    - uses: actions/checkout@v3
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ matrix.ruby }}
        bundler-cache: true
    - name: Set JRUBY_OPTS environment variable
      run: echo "JRUBY_OPTS=--debug" >> "$GITHUB_ENV"
      if: ${{ startsWith(matrix.ruby, 'jruby') }}
    - name: Run tests
      run: bundle exec rake
    - uses: actions/upload-artifact@v4
      if: ${{ matrix.os == 'ubuntu-latest' && matrix.ruby == '3.0' }}
      with:
        name: coverage
        path: coverage/
        retention-days: 1

  coveralls:
    needs: test
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
    - uses: actions/download-artifact@v4
      with:
        name: coverage
        path: coverage/
    - name: Coveralls GitHub Action
      uses: coverallsapp/github-action@v2


================================================
FILE: .gitignore
================================================
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
*.swp


================================================
FILE: .rspec
================================================
--colour
--format=progress


================================================
FILE: .rubocop.yml
================================================
AllCops:
  NewCops: enable

Gemspec/RequiredRubyVersion:
  Enabled: false

Layout/AccessModifierIndentation:
  EnforcedStyle: outdent

Layout/LineLength:
  AllowURI: true
  Enabled: false

Layout/SpaceInsideHashLiteralBraces:
  EnforcedStyle: no_space

Lint/MissingSuper:
  Enabled: false

Metrics/AbcSize:
  Max: 18

Metrics/BlockLength:
  Exclude:
    - spec/omniauth/strategies/oauth2_spec.rb

Metrics/BlockNesting:
  Max: 2

Metrics/ClassLength:
  Max: 110

Metrics/MethodLength:
  CountComments: false
  Max: 10

Metrics/ParameterLists:
  Max: 4
  CountKeywordArgs: true

Naming/FileName:
  Exclude:
    - lib/omniauth-oauth2.rb

Style/CollectionMethods:
  PreferredMethods:
    map:      'collect'
    reduce:   'inject'
    find:     'detect'
    find_all: 'select'

Style/Documentation:
  Enabled: false

Style/DoubleNegation:
  Enabled: false

Style/ExpandPathArguments:
  Enabled: false

Style/FrozenStringLiteralComment:
  Enabled: false

Style/HashSyntax:
  EnforcedStyle: hash_rockets

Style/StderrPuts:
  Enabled: false

Style/StringLiterals:
  EnforcedStyle: double_quotes

Style/TrailingCommaInArguments:
  EnforcedStyleForMultiline: comma

Style/TrailingCommaInHashLiteral:
  EnforcedStyleForMultiline: comma

Style/TrailingCommaInArrayLiteral:
  EnforcedStyleForMultiline: comma


================================================
FILE: CHANGELOG.md
================================================
## [v1.9.0](https://github.com/omniauth/omniauth-oauth2/releases/tag/v1.9.0)
- Prevent timing attacks [#174](https://github.com/omniauth/omniauth-oauth2/pull/174)
- Rescue OAuth2 timeouts [#169](https://github.com/omniauth/omniauth-oauth2/pull/169)

## [v1.8.0](https://github.com/omniauth/omniauth-oauth2/releases/tag/v1.8.0)
- Relaxes allowed versions of the oauth2 gem. [#146](https://github.com/omniauth/omniauth-oauth2/pull/146)
- Requires omniauth `~> 2.0` [#152](https://github.com/omniauth/omniauth-oauth2/pull/152) 

Please see https://github.com/omniauth/omniauth-oauth2/releases for changelog prior to 1.8.0


================================================
FILE: Gemfile
================================================
source "https://rubygems.org"

gem "rake", "~> 13.0"

group :test do
  gem "addressable", "~> 2.3.8", :platforms => %i[jruby ruby_18]
  gem 'coveralls_reborn', '~> 0.19.0', require: false
  gem "json", :platforms => %i[jruby ruby_18 ruby_19]
  gem "mime-types", "~> 1.25", :platforms => %i[jruby ruby_18]
  gem "rack-test"
  gem "rest-client", "~> 1.8.0", :platforms => %i[jruby ruby_18]
  gem "rspec", "~> 3.2"
  gem "rubocop", ">= 0.51", :platforms => %i[ruby_19 ruby_20 ruby_21 ruby_22 ruby_23 ruby_24]
  gem 'simplecov-lcov'
  gem 'tins', '~> 1.13', :platforms => %i[jruby_18 jruby_19 ruby_19]
  gem "webmock", "~> 3.0"
end

# Specify your gem's dependencies in omniauth-oauth2.gemspec
gemspec


================================================
FILE: LICENSE.md
================================================
Copyright (C) 2014 Michael Bleigh, Erik Michaels-Ober and Intridea, Inc.

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.


================================================
FILE: README.md
================================================
# OmniAuth OAuth2

[![Gem Version](http://img.shields.io/gem/v/omniauth-oauth2.svg)][gem]
[![Code Climate](http://img.shields.io/codeclimate/maintainability/intridea/omniauth-oauth2.svg)][codeclimate]
[![Coverage Status](http://img.shields.io/coveralls/intridea/omniauth-oauth2.svg)][coveralls]
[![Security](https://hakiri.io/github/omniauth/omniauth-oauth2/master.svg)](https://hakiri.io/github/omniauth/omniauth-oauth2/master)

[gem]: https://rubygems.org/gems/omniauth-oauth2
[codeclimate]: https://codeclimate.com/github/intridea/omniauth-oauth2
[coveralls]: https://coveralls.io/r/intridea/omniauth-oauth2

This gem contains a generic OAuth2 strategy for OmniAuth. It is meant to serve
as a building block strategy for other strategies and not to be used
independently (since it has no inherent way to gather uid and user info).

## Creating an OAuth2 Strategy

To create an OmniAuth OAuth2 strategy using this gem, you can simply subclass
it and add a few extra methods like so:

```ruby
require 'omniauth-oauth2'

module OmniAuth
  module Strategies
    class SomeSite < OmniAuth::Strategies::OAuth2
      # Give your strategy a name.
      option :name, "some_site"

      # This is where you pass the options you would pass when
      # initializing your consumer from the OAuth gem.
      option :client_options, {:site => "https://api.somesite.com"}

      # You may specify that your strategy should use PKCE by setting
      # the pkce option to true: https://tools.ietf.org/html/rfc7636
      option :pkce, true

      # These are called after authentication has succeeded. If
      # possible, you should try to set the UID without making
      # additional calls (if the user id is returned with the token
      # or as a URI parameter). This may not be possible with all
      # providers.
      uid{ raw_info['id'] }

      info do
        {
          :name => raw_info['name'],
          :email => raw_info['email']
        }
      end

      extra do
        {
          'raw_info' => raw_info
        }
      end

      def raw_info
        @raw_info ||= access_token.get('/me').parsed
      end
    end
  end
end
```

That's pretty much it!

## OmniAuth-OAuth2 for Enterprise

Available as part of the Tidelift Subscription.

The maintainers of OmniAuth-OAuth2 and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/rubygems-omniauth-oauth2?utm_source=undefined&utm_medium=referral&utm_campaign=enterprise)

## Supported Ruby Versions

OmniAuth is tested under 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, truffleruby, and JRuby.

================================================
FILE: Rakefile
================================================
#!/usr/bin/env rake

require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new

task :test => :spec

begin
  require "rubocop/rake_task"
  RuboCop::RakeTask.new
rescue LoadError
  task :rubocop do
    $stderr.puts "RuboCop is disabled"
  end
end

task :default => %i[spec rubocop]


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

Use this section to tell people about which versions of your project are
currently being supported with security updates.

| Version  | Supported          |
| -------  | ------------------ |
| 1.7.x    | :white_check_mark: |
| <= 1.6.x | :x:                |

## Security contact information

To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.


================================================
FILE: lib/omniauth/strategies/oauth2.rb
================================================
require "oauth2"
require "omniauth"
require "securerandom"
require "socket"       # for SocketError
require "timeout"      # for Timeout::Error

module OmniAuth
  module Strategies
    # Authentication strategy for connecting with APIs constructed using
    # the [OAuth 2.0 Specification](http://tools.ietf.org/html/draft-ietf-oauth-v2-10).
    # You must generally register your application with the provider and
    # utilize an application id and secret in order to authenticate using
    # OAuth 2.0.
    class OAuth2
      include OmniAuth::Strategy

      def self.inherited(subclass)
        OmniAuth::Strategy.included(subclass)
      end

      args %i[client_id client_secret]

      option :client_id, nil
      option :client_secret, nil
      option :client_options, {}
      option :authorize_params, {}
      option :authorize_options, %i[scope state]
      option :token_params, {}
      option :token_options, []
      option :auth_token_params, {}
      option :provider_ignores_state, false
      option :pkce, false
      option :pkce_verifier, nil
      option :pkce_options, {
        :code_challenge => proc { |verifier|
          Base64.urlsafe_encode64(
            Digest::SHA2.digest(verifier),
            :padding => false,
          )
        },
        :code_challenge_method => "S256",
      }

      attr_accessor :access_token

      def client
        ::OAuth2::Client.new(options.client_id, options.client_secret, deep_symbolize(options.client_options))
      end

      credentials do
        hash = {"token" => access_token.token}
        hash["refresh_token"] = access_token.refresh_token if access_token.expires? && access_token.refresh_token
        hash["expires_at"] = access_token.expires_at if access_token.expires?
        hash["expires"] = access_token.expires?
        hash
      end

      def request_phase
        redirect client.auth_code.authorize_url({:redirect_uri => callback_url}.merge(authorize_params))
      end

      def authorize_params # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
        options.authorize_params[:state] = SecureRandom.hex(24)

        if OmniAuth.config.test_mode
          @env ||= {}
          @env["rack.session"] ||= {}
        end

        params = options.authorize_params
                        .merge(options_for("authorize"))
                        .merge(pkce_authorize_params)

        session["omniauth.pkce.verifier"] = options.pkce_verifier if options.pkce
        session["omniauth.state"] = params[:state]

        params
      end

      def token_params
        options.token_params.merge(options_for("token")).merge(pkce_token_params)
      end

      def callback_phase # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
        error = request.params["error_reason"] || request.params["error"]
        if !options.provider_ignores_state && (request.params["state"].to_s.empty? || !secure_compare(request.params["state"], session.delete("omniauth.state")))
          fail!(:csrf_detected, CallbackError.new(:csrf_detected, "CSRF detected"))
        elsif error
          fail!(error, CallbackError.new(request.params["error"], request.params["error_description"] || request.params["error_reason"], request.params["error_uri"]))
        else
          self.access_token = build_access_token
          self.access_token = access_token.refresh! if access_token.expired?
          super
        end
      rescue ::OAuth2::Error, CallbackError => e
        fail!(:invalid_credentials, e)
      rescue ::Timeout::Error, ::Errno::ETIMEDOUT, ::OAuth2::TimeoutError, ::OAuth2::ConnectionError => e
        fail!(:timeout, e)
      rescue ::SocketError => e
        fail!(:failed_to_connect, e)
      end

    protected

      def pkce_authorize_params
        return {} unless options.pkce

        options.pkce_verifier = SecureRandom.hex(64)

        # NOTE: see https://tools.ietf.org/html/rfc7636#appendix-A
        {
          :code_challenge => options.pkce_options[:code_challenge]
                                    .call(options.pkce_verifier),
          :code_challenge_method => options.pkce_options[:code_challenge_method],
        }
      end

      def pkce_token_params
        return {} unless options.pkce

        {:code_verifier => session.delete("omniauth.pkce.verifier")}
      end

      def build_access_token
        verifier = request.params["code"]
        client.auth_code.get_token(verifier, {:redirect_uri => callback_url}.merge(token_params.to_hash(:symbolize_keys => true)), deep_symbolize(options.auth_token_params))
      end

      def deep_symbolize(options)
        options.each_with_object({}) do |(key, value), hash|
          hash[key.to_sym] = value.is_a?(Hash) ? deep_symbolize(value) : value
        end
      end

      def options_for(option)
        hash = {}
        options.send(:"#{option}_options").select { |key| options[key] }.each do |key|
          hash[key.to_sym] = if options[key].respond_to?(:call)
                               options[key].call(env)
                             else
                               options[key]
                             end
        end
        hash
      end

       # constant-time comparison algorithm to prevent timing attacks
       def secure_compare(string_a, string_b)
        return false unless string_a.bytesize == string_b.bytesize

        l = string_a.unpack "C#{string_a.bytesize}"

        res = 0
        string_b.each_byte { |byte| res |= byte ^ l.shift }
        res.zero?
      end

      # An error that is indicated in the OAuth 2.0 callback.
      # This could be a `redirect_uri_mismatch` or other
      class CallbackError < StandardError
        attr_accessor :error, :error_reason, :error_uri

        def initialize(error, error_reason = nil, error_uri = nil)
          self.error = error
          self.error_reason = error_reason
          self.error_uri = error_uri
        end

        def message
          [error, error_reason, error_uri].compact.join(" | ")
        end
      end
    end
  end
end

OmniAuth.config.add_camelization "oauth2", "OAuth2"


================================================
FILE: lib/omniauth-oauth2/version.rb
================================================
module OmniAuth
  module OAuth2
    VERSION = "1.9.0".freeze
  end
end


================================================
FILE: lib/omniauth-oauth2.rb
================================================
require "omniauth-oauth2/version"
require "omniauth/strategies/oauth2"


================================================
FILE: omniauth-oauth2.gemspec
================================================
lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "omniauth-oauth2/version"

Gem::Specification.new do |gem|
  gem.add_dependency "oauth2",  [">= 2.0.2", "< 3"]
  gem.add_dependency "omniauth", "~> 2.0"

  gem.add_development_dependency "bundler", "~> 4.0"

  gem.authors       = ["Michael Bleigh", "Erik Michaels-Ober", "Tom Milewski"]
  gem.email         = ["michael@intridea.com", "sferik@gmail.com", "tmilewski@gmail.com"]
  gem.description   = "An abstract OAuth2 strategy for OmniAuth."
  gem.summary       = gem.description
  gem.homepage      = "https://github.com/omniauth/omniauth-oauth2"
  gem.licenses      = %w[MIT]

  gem.executables   = `git ls-files -- bin/*`.split("\n").collect { |f| File.basename(f) }
  gem.files         = `git ls-files`.split("\n")
  gem.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
  gem.name          = "omniauth-oauth2"
  gem.require_paths = %w[lib]
  gem.version       = OmniAuth::OAuth2::VERSION
end


================================================
FILE: spec/helper.rb
================================================
$LOAD_PATH.unshift File.expand_path("..", __FILE__)
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)

if RUBY_VERSION >= "1.9"
  require "simplecov"
  require "simplecov-lcov"
  require "coveralls"

  SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true

  SimpleCov.formatters = [
    SimpleCov::Formatter::HTMLFormatter,
    SimpleCov::Formatter::LcovFormatter,
    Coveralls::SimpleCov::Formatter
  ]

  SimpleCov.start do
    minimum_coverage(78.48)
  end
end

require "rspec"
require "rack/test"
require "webmock/rspec"
require "omniauth"
require "omniauth-oauth2"

RSpec.configure do |config|
  config.expect_with :rspec do |c|
    c.syntax = :expect
  end
  config.extend OmniAuth::Test::StrategyMacros, :type => :strategy
  config.include Rack::Test::Methods
  config.include WebMock::API
end


================================================
FILE: spec/omniauth/strategies/oauth2_spec.rb
================================================
require "helper"

describe OmniAuth::Strategies::OAuth2 do
  def app
    lambda do |_env|
      [200, {}, ["Hello."]]
    end
  end
  let(:fresh_strategy) { Class.new(OmniAuth::Strategies::OAuth2) }

  before do
    OmniAuth.config.test_mode = true
  end

  after do
    OmniAuth.config.test_mode = false
  end

  describe "Subclassing Behavior" do
    subject { fresh_strategy }

    it "performs the OmniAuth::Strategy included hook" do
      expect(OmniAuth.strategies).to include(OmniAuth::Strategies::OAuth2)
      expect(OmniAuth.strategies).to include(subject)
    end
  end

  describe "#client" do
    subject { fresh_strategy }

    it "is initialized with symbolized client_options" do
      instance = subject.new(app, :client_options => {"authorize_url" => "https://example.com"})
      expect(instance.client.options[:authorize_url]).to eq("https://example.com")
    end

    it "sets ssl options as connection options" do
      instance = subject.new(app, :client_options => {"ssl" => {"ca_path" => "foo"}})
      expect(instance.client.options[:connection_opts][:ssl]).to eq(:ca_path => "foo")
    end
  end

  describe "#authorize_params" do
    subject { fresh_strategy }

    it "includes any authorize params passed in the :authorize_params option" do
      instance = subject.new("abc", "def", :authorize_params => {:foo => "bar", :baz => "zip"})
      expect(instance.authorize_params["foo"]).to eq("bar")
      expect(instance.authorize_params["baz"]).to eq("zip")
    end

    it "includes top-level options that are marked as :authorize_options" do
      instance = subject.new("abc", "def", :authorize_options => %i[scope foo state], :scope => "bar", :foo => "baz")
      expect(instance.authorize_params["scope"]).to eq("bar")
      expect(instance.authorize_params["foo"]).to eq("baz")
      expect(instance.authorize_params["state"]).not_to be_empty
    end

    it "includes random state in the authorize params" do
      instance = subject.new("abc", "def")
      expect(instance.authorize_params.keys).to eq(["state"])
      expect(instance.session["omniauth.state"]).not_to be_empty
    end

    it "includes custom state in the authorize params" do
      instance = subject.new("abc", "def", :state => proc { "qux" })
      expect(instance.authorize_params.keys).to eq(["state"])
      expect(instance.session["omniauth.state"]).to eq("qux")
    end

    it "includes PKCE parameters if enabled" do
      instance = subject.new("abc", "def", :pkce => true)
      expect(instance.authorize_params[:code_challenge]).to be_a(String)
      expect(instance.authorize_params[:code_challenge_method]).to eq("S256")
      expect(instance.session["omniauth.pkce.verifier"]).to be_a(String)
    end
  end

  describe "#token_params" do
    subject { fresh_strategy }

    it "includes any authorize params passed in the :authorize_params option" do
      instance = subject.new("abc", "def", :token_params => {:foo => "bar", :baz => "zip"})
      expect(instance.token_params).to eq("foo" => "bar", "baz" => "zip")
    end

    it "includes top-level options that are marked as :authorize_options" do
      instance = subject.new("abc", "def", :token_options => %i[scope foo], :scope => "bar", :foo => "baz")
      expect(instance.token_params).to eq("scope" => "bar", "foo" => "baz")
    end

    it "includes the PKCE code_verifier if enabled" do
      instance = subject.new("abc", "def", :pkce => true)
      # setup session
      instance.authorize_params
      expect(instance.token_params[:code_verifier]).to be_a(String)
    end
  end

  describe "#callback_phase" do
    subject(:instance) { fresh_strategy.new("abc", "def") }

    let(:params) { {"error_reason" => "user_denied", "error" => "access_denied", "state" => state} }
    let(:state) { "secret" }

    before do
      allow(instance).to receive(:request) do
        double("Request", :params => params)
      end

      allow(instance).to receive(:session) do
        double("Session", :delete => state)
      end
    end

    it "calls fail with the error received" do
      expect(instance).to receive(:fail!).with("user_denied", anything)

      instance.callback_phase
    end

    it "calls fail with the error received if state is missing and CSRF verification is disabled" do
      params["state"] = nil
      instance.options.provider_ignores_state = true

      expect(instance).to receive(:fail!).with("user_denied", anything)

      instance.callback_phase
    end

    it "calls fail with a CSRF error if the state is missing" do
      params["state"] = nil

      expect(instance).to receive(:fail!).with(:csrf_detected, anything)
      instance.callback_phase
    end

    it "calls fail with a CSRF error if the state is invalid" do
      params["state"] = "invalid"

      expect(instance).to receive(:fail!).with(:csrf_detected, anything)
      instance.callback_phase
    end

    describe 'exception handlings' do
      let(:params) do
        {"code" => "code", "state" => state}
      end

      before do
        allow_any_instance_of(OmniAuth::Strategies::OAuth2).to receive(:build_access_token).and_raise(exception)
      end

      {
        :invalid_credentials => [OAuth2::Error, OmniAuth::Strategies::OAuth2::CallbackError],
        :timeout => [Timeout::Error, Errno::ETIMEDOUT, OAuth2::TimeoutError, OAuth2::ConnectionError],
        :failed_to_connect => [SocketError]
      }.each do |error_type, exceptions|
        exceptions.each do |klass|
          context "when #{klass}" do
            let(:exception) { klass.new 'error' }

            it do
              expect(instance).to receive(:fail!).with(error_type, exception)
              instance.callback_phase
            end
          end
        end
      end
    end
  end

  describe "#secure_compare" do
    subject { fresh_strategy }

    it "returns true when the two inputs are the same and false otherwise" do
      instance = subject.new("abc", "def")
      expect(instance.send(:secure_compare, "a", "a")).to be true
      expect(instance.send(:secure_compare, "b", "a")).to be false
    end
  end
end

describe OmniAuth::Strategies::OAuth2::CallbackError do
  let(:error) { Class.new(OmniAuth::Strategies::OAuth2::CallbackError) }
  describe "#message" do
    subject { error }
    it "includes all of the attributes" do
      instance = subject.new("error", "description", "uri")
      expect(instance.message).to match(/error/)
      expect(instance.message).to match(/description/)
      expect(instance.message).to match(/uri/)
    end
    it "includes all of the attributes" do
      instance = subject.new(nil, :symbol)
      expect(instance.message).to eq("symbol")
    end
  end
end
Download .txt
gitextract_b905nxjk/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .rspec
├── .rubocop.yml
├── CHANGELOG.md
├── Gemfile
├── LICENSE.md
├── README.md
├── Rakefile
├── SECURITY.md
├── lib/
│   ├── omniauth/
│   │   └── strategies/
│   │       └── oauth2.rb
│   ├── omniauth-oauth2/
│   │   └── version.rb
│   └── omniauth-oauth2.rb
├── omniauth-oauth2.gemspec
└── spec/
    ├── helper.rb
    └── omniauth/
        └── strategies/
            └── oauth2_spec.rb
Download .txt
SYMBOL INDEX (21 symbols across 3 files)

FILE: lib/omniauth-oauth2/version.rb
  type OmniAuth (line 1) | module OmniAuth
    type OAuth2 (line 2) | module OAuth2

FILE: lib/omniauth/strategies/oauth2.rb
  type OmniAuth (line 7) | module OmniAuth
    type Strategies (line 8) | module Strategies
      class OAuth2 (line 14) | class OAuth2
        method inherited (line 17) | def self.inherited(subclass)
        method client (line 46) | def client
        method request_phase (line 58) | def request_phase
        method authorize_params (line 62) | def authorize_params # rubocop:disable Metrics/AbcSize, Metrics/Me...
        method token_params (line 80) | def token_params
        method callback_phase (line 84) | def callback_phase # rubocop:disable Metrics/AbcSize, Metrics/Cycl...
        method pkce_authorize_params (line 105) | def pkce_authorize_params
        method pkce_token_params (line 118) | def pkce_token_params
        method build_access_token (line 124) | def build_access_token
        method deep_symbolize (line 129) | def deep_symbolize(options)
        method options_for (line 135) | def options_for(option)
        method secure_compare (line 148) | def secure_compare(string_a, string_b)
        class CallbackError (line 160) | class CallbackError < StandardError
          method initialize (line 163) | def initialize(error, error_reason = nil, error_uri = nil)
          method message (line 169) | def message

FILE: spec/omniauth/strategies/oauth2_spec.rb
  function app (line 4) | def app
Condensed preview — 17 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 54,
    "preview": "github: bobbymcwho\ntidelift: rubygems/omniauth-oauth2\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 1202,
    "preview": "name: Ruby\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  test:\n    runs-on: ${"
  },
  {
    "path": ".gitignore",
    "chars": 160,
    "preview": "*.gem\n*.rbc\n.bundle\n.config\n.yardoc\nGemfile.lock\nInstalledFiles\n_yardoc\ncoverage\ndoc/\nlib/bundler/man\npkg\nrdoc\nspec/repo"
  },
  {
    "path": ".rspec",
    "chars": 27,
    "preview": "--colour\n--format=progress\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 1297,
    "preview": "AllCops:\n  NewCops: enable\n\nGemspec/RequiredRubyVersion:\n  Enabled: false\n\nLayout/AccessModifierIndentation:\n  EnforcedS"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 619,
    "preview": "## [v1.9.0](https://github.com/omniauth/omniauth-oauth2/releases/tag/v1.9.0)\n- Prevent timing attacks [#174](https://git"
  },
  {
    "path": "Gemfile",
    "chars": 698,
    "preview": "source \"https://rubygems.org\"\n\ngem \"rake\", \"~> 13.0\"\n\ngroup :test do\n  gem \"addressable\", \"~> 2.3.8\", :platforms => %i[j"
  },
  {
    "path": "LICENSE.md",
    "chars": 1097,
    "preview": "Copyright (C) 2014 Michael Bleigh, Erik Michaels-Ober and Intridea, Inc.\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "README.md",
    "chars": 2811,
    "preview": "# OmniAuth OAuth2\n\n[![Gem Version](http://img.shields.io/gem/v/omniauth-oauth2.svg)][gem]\n[![Code Climate](http://img.sh"
  },
  {
    "path": "Rakefile",
    "chars": 309,
    "preview": "#!/usr/bin/env rake\n\nrequire \"bundler/gem_tasks\"\nrequire \"rspec/core/rake_task\"\n\nRSpec::Core::RakeTask.new\n\ntask :test ="
  },
  {
    "path": "SECURITY.md",
    "chars": 495,
    "preview": "# Security Policy\n\n## Supported Versions\n\nUse this section to tell people about which versions of your project are\ncurre"
  },
  {
    "path": "lib/omniauth/strategies/oauth2.rb",
    "chars": 6155,
    "preview": "require \"oauth2\"\nrequire \"omniauth\"\nrequire \"securerandom\"\nrequire \"socket\"       # for SocketError\nrequire \"timeout\"   "
  },
  {
    "path": "lib/omniauth-oauth2/version.rb",
    "chars": 71,
    "preview": "module OmniAuth\n  module OAuth2\n    VERSION = \"1.9.0\".freeze\n  end\nend\n"
  },
  {
    "path": "lib/omniauth-oauth2.rb",
    "chars": 71,
    "preview": "require \"omniauth-oauth2/version\"\nrequire \"omniauth/strategies/oauth2\"\n"
  },
  {
    "path": "omniauth-oauth2.gemspec",
    "chars": 1024,
    "preview": "lib = File.expand_path(\"../lib\", __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire \"omniauth-oau"
  },
  {
    "path": "spec/helper.rb",
    "chars": 832,
    "preview": "$LOAD_PATH.unshift File.expand_path(\"..\", __FILE__)\n$LOAD_PATH.unshift File.expand_path(\"../../lib\", __FILE__)\n\nif RUBY_"
  },
  {
    "path": "spec/omniauth/strategies/oauth2_spec.rb",
    "chars": 6685,
    "preview": "require \"helper\"\n\ndescribe OmniAuth::Strategies::OAuth2 do\n  def app\n    lambda do |_env|\n      [200, {}, [\"Hello.\"]]\n  "
  }
]

About this extraction

This page contains the full source code of the omniauth/omniauth-oauth2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 17 files (23.1 KB), approximately 6.6k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!