Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport authorization procs to 1.x branch #1322

Merged
merged 2 commits into from Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/middleware/request/authentication.md
Expand Up @@ -23,6 +23,16 @@ Faraday.new(...) do |conn|
end
```

### With a proc

You can also provide a proc, which will be evaluated on each request:

```ruby
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', -> { MyAuthStorage.get_auth_token }
end
```

### Basic Authentication

`BasicAuthentication` adds a 'Basic' type Authorization header to a Faraday request.
Expand Down
45 changes: 39 additions & 6 deletions lib/faraday/request/authorization.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'base64'

module Faraday
class Request
# Request middleware for the Authorization HTTP header
Expand Down Expand Up @@ -39,16 +41,47 @@ def self.build_hash(type, hash)

# @param app [#call]
# @param type [String, Symbol] Type of Authorization
# @param token [String, Symbol, Hash] Token value for the Authorization
def initialize(app, type, token)
@header_value = self.class.header(type, token)
# @param params [Array<String, Proc>] parameters to build the Authorization header.
# If the type is `:basic`, then these can be a login and password pair.
# Otherwise, a single value is expected that will be appended after the type.
# This value can be a proc, in which case it will be invoked on each request.
def initialize(app, type, *params)
@type = type
@params = params
@header_value = self.class.header(type, params[0]) unless params[0].is_a? Proc
super(app)
end

# @param env [Faraday::Env]
def call(env)
env.request_headers[KEY] = @header_value unless env.request_headers[KEY]
@app.call(env)
def on_request(env)
return if env.request_headers[KEY]

env.request_headers[KEY] = header_from(@type, *@params)
end

private

# @param type [String, Symbol]
# @param params [Array]
# @return [String] a header value
def header_from(type, *params)
return @header_value if @header_value

if type.to_s.casecmp('basic').zero? && params.size == 2
basic_header_from(*params)
elsif params.size != 1
raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
else
value = params.first
value = value.call if value.is_a?(Proc)
"#{type} #{value}"
end
end

def basic_header_from(login, pass)
value = Base64.encode64("#{login}:#{pass}")
value.delete!("\n")
"Basic #{value}"
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions spec/faraday/request/authorization_spec.rb
Expand Up @@ -84,5 +84,13 @@

include_examples 'does not interfere with existing authentication'
end

context 'when passed a string and a proc' do
let(:auth_config) { ['Bearer', -> { 'custom_from_proc' }] }

it { expect(response.body).to eq('Bearer custom_from_proc') }

include_examples 'does not interfere with existing authentication'
end
end
end