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

Adding Bearer Token support #387

Merged
merged 9 commits into from
Apr 18, 2013
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions lib/twitter/api/oauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ module API
module OAuth
include Twitter::API::Utils

# Allows a registered application to obtain an OAuth 2 Bearer Token, which can be used to make API requests
# on an application's own behalf, without a user context.
#
# Only one bearer token may exist outstanding for an application, and repeated requests to this method
# will yield the same already-existent token until it has been invalidated.
#
# @see https://dev.twitter.com/docs/api/1.1/post/oauth2/token
# @rate_limited No
# @authentication Required
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Twitter::Token] The Bearer Token. token_type should be 'bearer'.
# @example Generate a Bearer Token
# client = Twitter::Client.new :consumer_key => "abc", :consumer_secret => 'def'
# bearer_token = client.token
def token
object_from_response(Twitter::Token, :bearer_request, "/oauth2/token", :grant_type => "client_credentials")
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe alias this method to bearer_token?


# Allows a registered application to revoke an issued OAuth 2 Bearer Token by presenting its client credentials.
#
# @see https://dev.twitter.com/docs/api/1.1/post/oauth2/invalidate_token
Expand Down
35 changes: 33 additions & 2 deletions lib/twitter/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ def request(method, path, params={}, signature_params=params)
raise Twitter::Error::DecodeError
end

def bearer_request(path, params={})
connection.send(:post, path, params) do |request|
request.headers[:authorization] = bearer_token_credentials_auth_header
request.headers[:content_type] = "application/x-www-form-urlencoded; charset=UTF-8"
request.headers[:accept] = "*/*"
end.env
rescue Faraday::Error::ClientError
raise Twitter::Error::ClientError
rescue MultiJson::DecodeError
raise Twitter::Error::DecodeError
end

# Returns a Faraday::Connection object
#
# @return [Faraday::Connection]
Expand All @@ -100,9 +112,28 @@ def connection
end
end

# Generates authentication header for a bearer token request
#
# @return [String]
def bearer_token_credentials_auth_header
credentials = Base64.strict_encode64("#{@consumer_key}:#{@consumer_secret}")
"Basic #{credentials}"
end

# Generates authentication header for when the :bearer_token is supplied
#
# @return [String]
def bearer_token_auth_header
"Bearer #{@bearer_token}"
end

def auth_header(method, path, params={})
uri = URI(@endpoint + path)
SimpleOAuth::Header.new(method, uri, params, credentials)
if application_only_auth?
bearer_token_auth_header
else
uri = URI(@endpoint + path)
SimpleOAuth::Header.new(method, uri, params, credentials)
end
end

end
Expand Down
9 changes: 7 additions & 2 deletions lib/twitter/configurable.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
require 'forwardable'
require 'twitter/error/configuration_error'
require 'base64'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This require statement belongs in client.rb, where the Base64 module is used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.


module Twitter
module Configurable
extend Forwardable
attr_writer :consumer_key, :consumer_secret, :oauth_token, :oauth_token_secret
attr_writer :consumer_key, :consumer_secret, :oauth_token, :oauth_token_secret, :bearer_token
attr_accessor :endpoint, :connection_options, :identity_map, :middleware
def_delegator :options, :hash

Expand All @@ -16,6 +17,7 @@ def keys
:consumer_secret,
:oauth_token,
:oauth_token_secret,
:bearer_token,
:endpoint,
:connection_options,
:identity_map,
Expand All @@ -37,7 +39,7 @@ def configure

# @return [Boolean]
def credentials?
credentials.values.all?
credentials.values.all? || @bearer_token
end

def reset!
Expand All @@ -49,6 +51,9 @@ def reset!
alias setup reset!

private
def application_only_auth?
!!@bearer_token
end

# @return [Hash]
def credentials
Expand Down
5 changes: 5 additions & 0 deletions lib/twitter/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ def oauth_token_secret
ENV['TWITTER_OAUTH_TOKEN_SECRET']
end

# @return [String]
def bearer_token
ENV['TWITTER_BEARER_TOKEN']
end

# @note This is configurable in case you want to use a Twitter-compatible endpoint.
# @see http://status.net/wiki/Twitter-compatible_API
# @see http://en.blog.wordpress.com/2009/12/12/twitter-api/
Expand Down
26 changes: 25 additions & 1 deletion spec/twitter/api/oauth_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,31 @@
describe Twitter::API::OAuth do

before do
@client = Twitter::Client.new
@client = Twitter::Client.new :consumer_key => 'CK', :consumer_secret => 'CS'
end

describe "#token" do
before do
# WebMock treats Basic Auth differently so we have to chack against the full url with credentials.
@oauth2_token_url = "https://CK:CS@api.twitter.com/oauth2/token"
stub_request(:post, @oauth2_token_url).with(:body => "grant_type=client_credentials").to_return(:body => '{"token_type" : "bearer", "access_token" : "AAAA%2FAAA%3DAAAAAAAA"}', :headers => {:content_type => "application/json; charset=utf-8"})
end
it "requests the correct resource" do
@client.token
expect(a_request(:post, @oauth2_token_url).with(:body => {:grant_type => "client_credentials"})).to have_been_made
end
it "requests with the correct headers" do
@client.token
expect(a_request(:post, @oauth2_token_url).with(:headers => {
:content_type => "application/x-www-form-urlencoded; charset=UTF-8",
:accept => "*/*"
})).to have_been_made
end
it "returns the bearer token" do
token = @client.token
expect(token.access_token).to eq "AAAA%2FAAA%3DAAAAAAAA"
expect(token.token_type).to eq "bearer"
end
end

describe "#invalidate_token" do
Expand Down
13 changes: 13 additions & 0 deletions spec/twitter/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
:middleware => Proc.new{},
:oauth_token => 'OT',
:oauth_token_secret => 'OS',
:bearer_token => 'BT',
:identity_map => ::Hash
}
end
Expand Down Expand Up @@ -152,4 +153,16 @@
end
end

describe "#auth_header" do
subject do
Twitter::Client.new(:bearer_token => "BT")
end

it "creates the correct auth headers with supplied bearer_token" do
uri = "/1.1/direct_messages.json"
authorization = subject.send(:auth_header, :get, uri)
expect(authorization).to eq "Bearer BT"
end
end

end
8 changes: 7 additions & 1 deletion spec/twitter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@
end

describe ".credentials?" do
it "returns true if all credentials are present" do
it "returns true if only bearer_token is supplied" do
Twitter.configure do |config|
config.bearer_token = 'BT'
end
expect(Twitter.credentials?).to be_true
end
it "returns true if all oauth credentials are present" do
Twitter.configure do |config|
config.consumer_key = 'CK'
config.consumer_secret = 'CS'
Expand Down