├── .codeclimate.yml ├── .github └── workflows │ └── ruby.yml ├── .gitignore ├── .simplecov ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── VERSION.txt ├── faraday_middleware-oauth2_refresh.gemspec ├── lib ├── faraday_middleware-oauth2_refresh.rb └── faraday_middleware │ └── oauth2_refresh.rb └── test └── test_setup.rb /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | # Save as .codeclimate.yml (note leading .) in project root directory 2 | languages: 3 | Ruby: true 4 | JavaScript: false 5 | PHP: false 6 | Python: false 7 | # exclude_paths: 8 | # - "foo/bar.rb" -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | name: ruby build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | workflow_dispatch: 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | ruby: ['2.5', '2.6', '2.7', 'jruby-head', 'ruby-head'] 17 | gemfile: ['Gemfile'] 18 | exclude: 19 | - ruby: 2.7 20 | gemfile: activesupport-4.2.x 21 | - ruby: ruby-head 22 | gemfile: activesupport-4.2.x 23 | - ruby: jruby-head 24 | gemfile: activesupport-4.2.x 25 | env: 26 | BUNDLE_GEMFILE: ${{ matrix.gemfile }} 27 | name: Ruby ${{ matrix.ruby }} with ${{ matrix.gemfile }} 28 | steps: 29 | - uses: actions/checkout@v3 30 | - name: Set up Ruby 31 | uses: ruby/setup-ruby@v1 32 | with: 33 | ruby-version: ${{ matrix.ruby }} 34 | bundler-cache: true 35 | - name: Run tests 36 | run: bundle exec rake 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | *.gem 3 | coverage 4 | 5 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | 3 | SimpleCov.formatter = Coveralls::SimpleCov::Formatter 4 | SimpleCov.start do 5 | add_filter "/test/" 6 | end -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | --------- 3 | - **2016-11-21**: 0.0.4 4 | - Add VersionEye reference tracking 5 | - **2016-08-23**: 0.0.3 6 | - Update dependencies 7 | - **2015-05-31**: 0.0.2 8 | - Update dependencies 9 | - **2015-05-31**: 0.0.1 10 | - Initial release 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at johncwang@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2025 John Wang 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FaradayMiddleware::OAuth2Refresh 2 | 3 |
4 | 5 | [![Gem Version][gem-version-svg]][gem-version-url] 6 | [![Build Status][build-status-svg]][build-status-url] 7 | [![Coverage Status][coverage-status-svg]][coverage-status-url] 8 | 9 |
10 |
11 | 12 | [![Code Climate][codeclimate-status-svg]][codeclimate-status-url] 13 | [![Scrutinizer Code Quality][scrutinizer-status-svg]][scrutinizer-status-url] 14 | 15 |
16 |
17 | 18 | [![Docs][docs-rubydoc-svg]][docs-rubydoc-url] 19 | [![License][license-svg]][license-url] 20 | 21 |
22 | 23 | Faraday middleware to manage OAuth token authorization with token refresh. 24 | 25 | ## Description 26 | 27 | This gem is a piece of Faraday middleware that adds OAuth token handling using the [oauth2 gem](https://gitlab.com/oauth-xx/oauth2/). 28 | 29 | ## Installation 30 | 31 | Add this line to your application's Gemfile: 32 | 33 | ```ruby 34 | gem 'faraday_middleware-oauth2_refresh' 35 | ``` 36 | 37 | And then execute: 38 | 39 | ```sh 40 | $ bundle 41 | ``` 42 | 43 | Or install it yourself as: 44 | 45 | ```sh 46 | $ gem install faraday_middleware-oauth2_refresh 47 | ``` 48 | 49 | ## Usage 50 | 51 | ```ruby 52 | require 'oauth2' 53 | require 'faraday_middleware/oauth2_refresh' 54 | 55 | client = OAuth2::Client.new('my_client_id', 'my_client_secret', site: 'https://example.com' ) 56 | token = client.password.get_token('username', 'password', { headers: { 'Authorization' => 'Basic my_api_key' } }) 57 | 58 | conn = Faraday.new(url: "http://example.com") do |builder| 59 | builder.request :oauth2_refresh, token 60 | builder.adapter Faraday.default_adapter 61 | end 62 | 63 | conn.get "/foo" # sends token 64 | ``` 65 | 66 | ## Change Log 67 | 68 | See [CHANGELOG.md](CHANGELOG.md) 69 | 70 | ## Links 71 | 72 | Project Repo 73 | 74 | * https://github.com/grokify/faraday_middleware-oauth2_refresh 75 | 76 | ## Problems, Comments, Suggestions, Contributions? 77 | 78 | Any reports of problems, comments or suggestions are most welcome. 79 | 80 | Please report these on [Github](https://github.com/grokify/faraday_middleware-oauth2_refresh) 81 | 82 | ## License 83 | 84 | `FaradayMiddleware::OAuth2Refresh` is available under an MIT-style license. See {file:LICENSE.md} for details. 85 | 86 | `FaradayMiddleware::OAuth2Refresh` © 2015-2023 by John Wang 87 | 88 | [gem-version-svg]: https://badge.fury.io/rb/faraday_middleware-oauth2_refresh.svg 89 | [gem-version-url]: http://badge.fury.io/rb/faraday_middleware-oauth2_refresh 90 | [downloads-svg]: http://ruby-gem-downloads-badge.herokuapp.com/faraday_middleware-oauth2_refresh 91 | [downloads-url]: https://rubygems.org/gems/faraday_middleware-oauth2_refresh 92 | [build-status-svg]: https://github.com/grokify/faraday_middleware-oauth2_refresh/workflows/ruby%20build/badge.svg?branch=master 93 | [build-status-url]: https://github.com/grokify/faraday_middleware-oauth2_refresh/actions 94 | [coverage-status-svg]: https://coveralls.io/repos/grokify/faraday_middleware-oauth2_refresh/badge.svg?branch=master 95 | [coverage-status-url]: https://coveralls.io/r/grokify/faraday_middleware-oauth2_refresh?branch=master 96 | [dependency-status-svg]: https://gemnasium.com/grokify/faraday_middleware-oauth2_refresh.svg 97 | [dependency-status-url]: https://gemnasium.com/grokify/faraday_middleware-oauth2_refresh 98 | [codacy-svg]: https://api.codacy.com/project/badge/Grade/88aedf52809d460891546fc7e11bd2c6 99 | [codacy-url]: https://app.codacy.com/manual/grokify/faraday_middleware-oauth2_refresh/dashboard 100 | [codeclimate-status-svg]: https://codeclimate.com/github/grokify/faraday_middleware-oauth2_refresh/badges/gpa.svg 101 | [codeclimate-status-url]: https://codeclimate.com/github/grokify/faraday_middleware-oauth2_refresh 102 | [scrutinizer-status-svg]: https://scrutinizer-ci.com/g/grokify/faraday_middleware-oauth2_refresh/badges/quality-score.png?b=master 103 | [scrutinizer-status-url]: https://scrutinizer-ci.com/g/grokify/faraday_middleware-oauth2_refresh/?branch=master 104 | [references-svg]: https://www.versioneye.com/ruby/faraday_middleware-oauth2_refresh/reference_badge.svg 105 | [references-url]: https://www.versioneye.com/ruby/faraday_middleware-oauth2_refresh/ 106 | [docs-rubydoc-svg]: https://img.shields.io/badge/docs-rubydoc-blue.svg 107 | [docs-rubydoc-url]: http://www.rubydoc.info/gems/faraday_middleware-oauth2_refresh/ 108 | [license-svg]: https://img.shields.io/badge/license-MIT-blue.svg 109 | [license-url]: https://github.com/grokify/faraday_middleware-oauth2_refresh/blob/master/LICENSE.txt 110 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | 4 | desc 'Default: run unit tests.' 5 | task :default => :test 6 | 7 | desc 'Test the library.' 8 | Rake::TestTask.new do |t| 9 | t.libs << 'lib' 10 | t.pattern = 'test/**/test_*.rb' 11 | t.verbose = false 12 | end 13 | 14 | desc 'Generate YARD documentation.' 15 | task :gendoc do 16 | # puts 'yard doc generation disabled until JRuby build native extensions for redcarpet or yard removes the dependency.' 17 | system "yardoc" 18 | system "yard stats --list-undoc" 19 | end -------------------------------------------------------------------------------- /VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.1.0 -------------------------------------------------------------------------------- /faraday_middleware-oauth2_refresh.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'faraday_middleware-oauth2_refresh' 3 | s.version = '0.1.3' 4 | s.date = '2023-02-14' 5 | s.summary = 'Faraday OAuth2 request middleware with token refresh' 6 | s.description = 'This Faraday middleware gem adds OAuth2 token handling with token refresh' 7 | s.authors = ['John Wang'] 8 | s.email = 'johncwang@gmail.com' 9 | s.homepage = 'https://github.com/grokify/faraday_middleware-oauth2_refresh' 10 | s.licenses = ['MIT'] 11 | s.files = [ 12 | 'CHANGELOG.md', 13 | 'CODE_OF_CONDUCT.md', 14 | 'LICENSE.txt', 15 | 'README.md', 16 | 'Rakefile', 17 | 'VERSION.txt', 18 | 'lib/faraday_middleware-oauth2_refresh.rb', 19 | 'lib/faraday_middleware/oauth2_refresh.rb', 20 | 'test/test_setup.rb' 21 | ] 22 | s.required_ruby_version = '>= 2.0.0' 23 | 24 | s.add_dependency 'faraday', '~> 1.10', '>= 1.10.3' 25 | s.add_dependency 'faraday_middleware', '~> 1.2', '>= 1.2.0' 26 | 27 | s.add_development_dependency 'coveralls', '~> 0' 28 | s.add_development_dependency 'rake', '~> 13', '>= 13.0.6' 29 | s.add_development_dependency 'simplecov', '~> 0' 30 | s.add_development_dependency 'test-unit', '~> 3' 31 | end 32 | -------------------------------------------------------------------------------- /lib/faraday_middleware-oauth2_refresh.rb: -------------------------------------------------------------------------------- 1 | require 'faraday_middleware/oauth2_refresh' -------------------------------------------------------------------------------- /lib/faraday_middleware/oauth2_refresh.rb: -------------------------------------------------------------------------------- 1 | require 'base64' 2 | require 'faraday' 3 | require 'forwardable' 4 | 5 | module FaradayMiddleware 6 | class OAuth2Refresh < Faraday::Middleware 7 | AUTH_HEADER = 'Authorization'.freeze 8 | 9 | attr_reader :oauth2_token 10 | 11 | extend Forwardable 12 | 13 | def call(env) 14 | if @oauth2_token.expired? 15 | @oauth2_token = @oauth2_token.refresh!({ headers: { 'Authorization' => 'Basic ' + get_api_key() } }) 16 | end 17 | 18 | unless @oauth2_token.token.to_s.empty? 19 | env[:request_headers][AUTH_HEADER] = %(Bearer #{@oauth2_token.token}) 20 | end 21 | 22 | @app.call env 23 | end 24 | 25 | def get_api_key 26 | api_key = Base64.encode64("#{@oauth2_token.client.id}:#{@oauth2_token.client.secret}").gsub(/[\s]/,'') 27 | return api_key 28 | end 29 | 30 | def initialize(app = nil, token = nil) 31 | super app 32 | @oauth2_token = token 33 | end 34 | 35 | end 36 | end 37 | 38 | Faraday::Request.register_middleware oauth2_refresh: FaradayMiddleware::OAuth2Refresh 39 | -------------------------------------------------------------------------------- /test/test_setup.rb: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | Coveralls.wear! 3 | 4 | require 'test/unit' 5 | require 'faraday' 6 | require 'faraday_middleware' 7 | require 'faraday_middleware-oauth2_refresh' 8 | 9 | class OAuth2Test < Test::Unit::TestCase 10 | def test_setup 11 | 12 | Faraday.new 'http://example.com/api' do |conn| 13 | conn.request :oauth2_refresh 14 | end 15 | 16 | ref = FaradayMiddleware::OAuth2Refresh.new 17 | 18 | assert_equal 'FaradayMiddleware::OAuth2Refresh', ref.class.name 19 | 20 | end 21 | end 22 | --------------------------------------------------------------------------------