oauth2 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1 @@
1
+ require 'autotest/bundler'
data/.gitignore CHANGED
@@ -32,4 +32,7 @@ Gemfile.lock
32
32
  coverage.data
33
33
 
34
34
  ## PROJECT::SPECIFIC
35
- .svn
35
+ .svn
36
+
37
+ ## Rubinius
38
+ *.rbc
data/.travis.yml CHANGED
@@ -1,7 +1,5 @@
1
1
  rvm:
2
2
  - 1.8.7
3
- - 1.9.1
4
3
  - 1.9.2
5
- - jruby
6
- - rbx
7
4
  - ree
5
+ - ruby-head
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -8,7 +8,7 @@ Installation
8
8
 
9
9
  Continuous Integration
10
10
  ----------------------
11
- [![Build Status](http://travis-ci.org/intridea/oauth2.png)](http://travis-ci.org/intridea/oauth2)
11
+ [![Build Status](https://secure.travis-ci.org/intridea/oauth2.png)](http://travis-ci.org/intridea/oauth2)
12
12
 
13
13
  Resources
14
14
  ---------
@@ -16,67 +16,48 @@ Resources
16
16
  * Report Issues on GitHub (https://github.com/intridea/oauth2/issues)
17
17
  * Read More at the Wiki (https://wiki.github.com/intridea/oauth2)
18
18
 
19
- Web Server Example (Sinatra)
20
- ----------------------------
21
- Below is a fully functional example of a Sinatra application that would authenticate to Facebook utilizing the OAuth 2.0 web server flow.
19
+ Generic Client Example
20
+ ----------------------
22
21
 
23
- require 'rubygems'
24
- require 'sinatra'
25
22
  require 'oauth2'
26
- require 'json'
27
-
28
- def client
29
- OAuth2::Client.new('app_id', 'app_secret', :site => 'https://graph.facebook.com')
30
- end
31
-
32
- get '/auth/facebook' do
33
- redirect client.web_server.authorize_url(
34
- :redirect_uri => redirect_uri,
35
- :scope => 'email,offline_access'
36
- )
37
- end
38
-
39
- get '/auth/facebook/callback' do
40
- access_token = client.web_server.get_access_token(params[:code], :redirect_uri => redirect_uri)
41
- user = JSON.parse(access_token.get('/me'))
42
- user.inspect
43
- end
44
-
45
- def redirect_uri
46
- uri = URI.parse(request.url)
47
- uri.path = '/auth/facebook/callback'
48
- uri.query = nil
49
- uri.to_s
50
- end
51
-
52
- That's all there is to it! You can use the access token like you would with the
53
- OAuth gem, calling HTTP verbs on it etc. You can view more examples on the [OAuth2
54
- Wiki](http://wiki.github.com/intridea/oauth2/examples).
55
-
56
- JSON Parsing
57
- ------------
58
- Because JSON has become the standard format of the OAuth 2.0 specification,
59
- the <tt>oauth2</tt> gem contains a mode that will perform automatic parsing
60
- of JSON response bodies, returning a hash instead of a string. To enable this
61
- mode, simply add the <tt>:parse_json</tt> option to your client initialization:
23
+ client = OAuth2::Client.new('client_id', 'client_secret', :site => 'https://example.org')
24
+
25
+ client.auth_code.authorize_url(:redirect_uri => 'http://localhost:8080/oauth2/callback')
26
+ # => "https://example.org/oauth/authorization?response_type=code&client_id=client_id&redirect_uri=http://localhost:8080/oauth2/callback"
27
+
28
+ token = client.auth_code.get_token('authorization_code_value', :redirect_uri => 'http://localhost:8080/oauth2/callback')
29
+ response = token.get('/api/resource', :params => { 'query_foo' => 'bar' })
30
+ response.class.name
31
+ # => OAuth2::Response
32
+
33
+ OAuth2::Response
34
+ ----------------
35
+ The AccessToken methods #get, #post, #put and #delete and the generic #request will return an instance of the #OAuth2::Response class.
36
+ This instance contains a #parsed method that will parse the response body and return a Hash if the Content-Type is application/x-www-form-urlencoded or if the body is a JSON object. It will return an Array if the body is a JSON array. Otherwise, it will return the original body string.
37
+
38
+ The original response body, headers, and status can be accessed via their respective methods.
39
+
40
+ OAuth2::AccessToken
41
+ -------------------
42
+ If you have an existing Access Token for a user, you can initialize an instance using various class methods including the standard new, from_hash (if you have a hash of the values), or from_kvform (if you have an application/x-www-form-urlencoded encoded string of the values).
43
+
44
+ OAuth2::Error
45
+ -------------
46
+ On 400+ status code responses, an OAuth2::Error will be raised. If it is a standard OAuth2 error response, the body will be parsed and #code and #description will contain the values provided from the error and error_description parameters. The #response property of OAuth2::Error will always contain the OAuth2::Response instance.
62
47
 
63
- client = OAuth2::Client.new(
64
- 'app_id',
65
- 'app_secret',
66
- :site => 'https://example.com',
67
- :parse_json => true,
68
- )
69
-
70
- # Obtain an access token using the client
71
- token.get('/some/url.json') #=> {"some" => "hash"}
48
+ If you do not want an error to be raised, you may use :raise_errors => false option on initialization of the client. In this case the OAuth2::Response instance will be returned as usual and on 400+ status code responses, the Response instance will contain the OAuth2::Error instance.
72
49
 
73
- Testing
74
- -------
75
- To use the OAuth2 client for testing error conditions do:
50
+ Authorization Grants
51
+ --------------------
52
+ Currently the Authorization Code and Resource Owner Password Credentials authentication grant types have helper strategy classes that simplify client use. They are available via the #auth_code and #password methods respectively.
76
53
 
77
- my_client.raise_errors = false
54
+ auth_url = client.auth_code.authorization_url(:redirect_uri => 'http://localhost:8080/oauth/callback')
55
+ token = client.auth_code.get_token('code_value', :redirect_uri => 'http://localhost:8080/oauth/callback')
56
+
57
+ token = client.password.get_token('username', 'password')
58
+
59
+ You can always use the #request method on the OAuth2::Client instance to make requests for tokens for any Authentication grant type.
78
60
 
79
- It will then return the error status and response instead of raising an exception.
80
61
 
81
62
  Note on Patches/Pull Requests
82
63
  -----------------------------
@@ -87,7 +68,31 @@ Note on Patches/Pull Requests
87
68
  5. Add specs for your feature or bug fix.
88
69
  6. Run <tt>bundle exec rake spec</tt>. If your changes are not 100% covered, go back to step 5.
89
70
  7. Commit and push your changes.
90
- 8. Submit a pull request. Please do not include changes to the [gemspec](https://github.com/intridea/oauth2/blob/master/oauth2.gemspec), [version](https://github.com/intridea/oauth2/blob/master/lib/oauth2/version.rb), or [changelog](https://github.com/intridea/oauth2/blob/master/CHANGELOG.md) file. (If you want to create your own version for some reason, please do so in a separate commit.)
71
+ 8. Submit a pull request. Please do not include changes to the [gemspec](https://github.com/intridea/oauth2/blob/master/oauth2.gemspec), [version](https://github.com/intridea/oauth2/blob/master/lib/oauth2/version.rb), or [changelog](https://github.com/intridea/oauth2/wiki/Changelg) . (If you want to create your own version for some reason, please do so in a separate commit.)
72
+
73
+ Supported Rubies
74
+ ----------------
75
+ This library aims to support and is [tested
76
+ against](http://travis-ci.org/intridea/oauth2) the following Ruby
77
+ implementations:
78
+
79
+ * Ruby 1.8.7
80
+ * Ruby 1.9.2
81
+ * Ruby Enterprise Edition 1.8.7
82
+
83
+ If something doesn't work on one of these interpreters, it should be considered
84
+ a bug.
85
+
86
+ This library may inadvertently work (or seem to work) on other Ruby
87
+ implementations, however support will only be provided for the versions listed
88
+ above.
89
+
90
+ If you would like this library to support another Ruby version, you may
91
+ volunteer to be a maintainer. Being a maintainer entails making sure all tests
92
+ run and pass on that implementation. When something breaks on your
93
+ implementation, you will be personally responsible for providing patches in a
94
+ timely fashion. If critical issues for a particular implementation exist at the
95
+ time of a major release, support for that Ruby version may be dropped.
91
96
 
92
97
  Copyright
93
98
  ---------
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env rake
2
+
1
3
  require 'bundler'
2
4
  Bundler::GemHelper.install_tasks
3
5
 
@@ -7,7 +9,7 @@ RSpec::Core::RakeTask.new(:spec)
7
9
  task :default => :spec
8
10
  task :test => :spec
9
11
 
10
- require 'rake/rdoctask'
12
+ require 'rdoc/task'
11
13
  Rake::RDocTask.new do |rdoc|
12
14
  rdoc.rdoc_dir = 'rdoc'
13
15
  rdoc.title = "oauth2 #{OAuth2::VERSION}"
data/lib/oauth2.rb CHANGED
@@ -1,13 +1,7 @@
1
- module OAuth2
2
- class ErrorWithResponse < StandardError; attr_accessor :response end
3
- class AccessDenied < ErrorWithResponse; end
4
- class Conflict < ErrorWithResponse; end
5
- class HTTPError < ErrorWithResponse; end
6
- end
7
-
1
+ require 'oauth2/error'
8
2
  require 'oauth2/client'
9
3
  require 'oauth2/strategy/base'
10
- require 'oauth2/strategy/web_server'
4
+ require 'oauth2/strategy/auth_code'
11
5
  require 'oauth2/strategy/password'
12
6
  require 'oauth2/access_token'
13
- require 'oauth2/response_object'
7
+ require 'oauth2/response'
@@ -1,53 +1,151 @@
1
1
  module OAuth2
2
2
  class AccessToken
3
3
  attr_reader :client, :token, :refresh_token, :expires_in, :expires_at, :params
4
- attr_accessor :token_param
4
+ attr_accessor :options
5
5
 
6
- def initialize(client, token, refresh_token=nil, expires_in=nil, params={})
6
+ class << self
7
+ # Initializes an AccessToken from a Hash
8
+ #
9
+ # @param [Client] the OAuth2::Client instance
10
+ # @param [Hash] a hash of AccessToken property values
11
+ # @return [AccessToken] the initalized AccessToken
12
+ def from_hash(client, hash)
13
+ self.new(client, hash.delete('access_token') || hash.delete(:access_token), hash)
14
+ end
15
+
16
+ # Initializes an AccessToken from a key/value application/x-www-form-urlencoded string
17
+ #
18
+ # @param [Client] client the OAuth2::Client instance
19
+ # @param [String] kvform the application/x-www-form-urlencoded string
20
+ # @return [AccessToken] the initalized AccessToken
21
+ def from_kvform(client, kvform)
22
+ from_hash(client, Rack::Utils.parse_query(kvform))
23
+ end
24
+ end
25
+
26
+ # Initalize an AccessToken
27
+ #
28
+ # @param [Client] client the OAuth2::Client instance
29
+ # @param [String] token the Access Token value
30
+ # @param [Hash] opts the options to create the Access Token with
31
+ # @option opts [String] :refresh_token (nil) the refresh_token value
32
+ # @option opts [FixNum, String] :expires_in (nil) the number of seconds in which the AccessToken will expire
33
+ # @option opts [FixNum, String] :expires_at (nil) the epoch time in seconds in which AccessToken will expire
34
+ # @option opts [Symbol] :mode (:header) the transmission mode of the Access Token parameter value
35
+ # one of :header, :body or :query
36
+ # @option opts [String] :header_format ('Bearer %s') the string format to use for the Authorization header
37
+ # @option opts [String] :param_name ('bearer_token') the parameter name to use for transmission of the
38
+ # Access Token value in :body or :query transmission mode
39
+ def initialize(client, token, opts={})
7
40
  @client = client
8
41
  @token = token.to_s
9
- @refresh_token = refresh_token.to_s
10
- @expires_in = (expires_in.nil? || expires_in == '') ? nil : expires_in.to_i
11
- @expires_at = Time.now + @expires_in if @expires_in
12
- @params = params
13
- @token_param = 'oauth_token'
42
+ [:refresh_token, :expires_in, :expires_at].each do |arg|
43
+ instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s))
44
+ end
45
+ @expires_in ||= opts.delete('expires')
46
+ @expires_in &&= @expires_in.to_i
47
+ @expires_at ||= Time.now.to_i + @expires_in if @expires_in
48
+ @options = {:mode => opts.delete(:mode) || :header,
49
+ :header_format => opts.delete(:header_format) || 'Bearer %s',
50
+ :param_name => opts.delete(:param_name) || 'bearer_token'}
51
+ @params = opts
14
52
  end
15
53
 
54
+ # Indexer to additional params present in token response
55
+ #
56
+ # @param [String] key entry key to Hash
16
57
  def [](key)
17
58
  @params[key]
18
59
  end
19
60
 
20
- # True if the token in question has an expiration time.
61
+ # Whether or not the token expires
62
+ #
63
+ # @return [Boolean]
21
64
  def expires?
22
- !!@expires_in
65
+ !!@expires_at
23
66
  end
24
67
 
68
+ # Whether or not the token is expired
69
+ #
70
+ # @return [Boolean]
25
71
  def expired?
26
- expires? && expires_at < Time.now
72
+ expires? && (expires_at < Time.now.to_i)
27
73
  end
28
74
 
29
- def request(verb, path, params={}, headers={})
30
- if params.instance_of?(Hash)
31
- params = params.merge token_param => @token
32
- end
33
- headers = headers.merge 'Authorization' => "OAuth #{@token}"
34
- @client.request(verb, path, params, headers)
75
+ # Refreshes the current Access Token
76
+ #
77
+ # @return [AccessToken] a new AccessToken
78
+ # @note options should be carried over to the new AccessToken
79
+ def refresh!(params={})
80
+ raise "A refresh_token is not available" unless refresh_token
81
+ params.merge!(:client_id => @client.id,
82
+ :client_secret => @client.secret,
83
+ :grant_type => 'refresh_token',
84
+ :refresh_token => refresh_token)
85
+ new_token = @client.get_token(params)
86
+ new_token.options = options
87
+ new_token
88
+ end
89
+
90
+ # Make a request with the Access Token
91
+ #
92
+ # @param [Symbol] verb the HTTP request method
93
+ # @param [String] path the HTTP URL path of the request
94
+ # @param [Hash] opts the options to make the request with
95
+ # @see Client#request
96
+ def request(verb, path, opts={}, &block)
97
+ set_token(opts)
98
+ @client.request(verb, path, opts, &block)
35
99
  end
36
100
 
37
- def get(path, params={}, headers={})
38
- request(:get, path, params, headers)
101
+ # Make a GET request with the Access Token
102
+ #
103
+ # @see AccessToken#request
104
+ def get(path, opts={}, &block)
105
+ request(:get, path, opts, &block)
39
106
  end
40
107
 
41
- def post(path, params={}, headers={})
42
- request(:post, path, params, headers)
108
+ # Make a POST request with the Access Token
109
+ #
110
+ # @see AccessToken#request
111
+ def post(path, opts={}, &block)
112
+ request(:post, path, opts, &block)
43
113
  end
44
114
 
45
- def put(path, params={}, headers={})
46
- request(:put, path, params, headers)
115
+ # Make a PUT request with the Access Token
116
+ #
117
+ # @see AccessToken#request
118
+ def put(path, opts={}, &block)
119
+ request(:put, path, opts, &block)
47
120
  end
48
121
 
49
- def delete(path, params={}, headers={})
50
- request(:delete, path, params, headers)
122
+ # Make a DELETE request with the Access Token
123
+ #
124
+ # @see AccessToken#request
125
+ def delete(path, opts={}, &block)
126
+ request(:delete, path, opts, &block)
127
+ end
128
+
129
+ private
130
+ def set_token(opts)
131
+ case options[:mode]
132
+ when :header
133
+ opts[:headers] ||= {}
134
+ opts[:headers]['Authorization'] = options[:header_format] % token
135
+ when :query
136
+ opts[:params] ||= {}
137
+ opts[:params][options[:param_name]] = token
138
+ when :body
139
+ opts[:body] ||= {}
140
+ if opts[:body].is_a?(Hash)
141
+ opts[:body][options[:param_name]] = token
142
+ else
143
+ opts[:body] << "&#{options[:param_name]}=#{token}"
144
+ end
145
+ # @todo support for multi-part (file uploads)
146
+ else
147
+ raise "invalid :mode option of #{options[:mode]}"
148
+ end
51
149
  end
52
150
  end
53
151
  end
data/lib/oauth2/client.rb CHANGED
@@ -1,105 +1,146 @@
1
1
  require 'faraday'
2
2
 
3
3
  module OAuth2
4
+ # The OAuth2::Client class
4
5
  class Client
5
- attr_accessor :id, :secret, :site, :connection, :options, :raise_errors, :token_method
6
- attr_writer :json
6
+ attr_reader :id, :secret
7
+ attr_accessor :site, :connection, :options
7
8
 
8
9
  # Instantiate a new OAuth 2.0 client using the
9
- # client ID and client secret registered to your
10
+ # Client ID and Client Secret registered to your
10
11
  # application.
11
12
  #
12
- # Options:
13
+ # @param [String] client_id the client_id value
14
+ # @param [String] client_secret the client_secret value
15
+ # @param [Hash] opts the options to create the client with
16
+ # @option opts [String] :site the OAuth2 provider site host
17
+ # @option opts [String] :authorize_url ('/oauth/authorize') absolute or relative URL path to the Authorization endpoint
18
+ # @option opts [String] :token_url ('/oauth/token') absolute or relative URL path to the Token endpoint
19
+ # @option opts [Symbol] :token_method (:post) HTTP method to use to request token (:get or :post)
20
+ # @option opts [Hash] :connection_opts ({}) Hash of connection options to pass to initialize Faraday with
21
+ # @option opts [FixNum] :max_redirects (5) maximum number of redirects to follow
22
+ # @option opts [Boolean] :raise_errors (true) whether or not to raise an OAuth2::Error
23
+ # on responses with 400+ status codes
24
+ # @yield [builder] The Faraday connection builder
25
+ def initialize(client_id, client_secret, opts={}, &block)
26
+ @id = client_id
27
+ @secret = client_secret
28
+ @site = opts.delete(:site)
29
+ ssl = opts.delete(:ssl)
30
+ @options = {:authorize_url => '/oauth/authorize',
31
+ :token_url => '/oauth/token',
32
+ :token_method => :post,
33
+ :connection_opts => {},
34
+ :connection_build => block,
35
+ :max_redirects => 5,
36
+ :raise_errors => true}.merge(opts)
37
+ @options[:connection_opts][:ssl] = ssl if ssl
38
+ end
39
+
40
+ # Set the site host
13
41
  #
14
- # <tt>:site</tt> :: Specify a base URL for your OAuth 2.0 client.
15
- # <tt>:authorize_path</tt> :: Specify the path to the authorization endpoint.
16
- # <tt>:authorize_url</tt> :: Specify a full URL of the authorization endpoint.
17
- # <tt>:access_token_path</tt> :: Specify the path to the access token endpoint.
18
- # <tt>:access_token_method</tt> :: Specify the method to use for token endpoints, can be :get or :post
19
- # (note: for Facebook this should be :get and for Google this should be :post)
20
- # <tt>:access_token_url</tt> :: Specify the full URL of the access token endpoint.
21
- # <tt>:parse_json</tt> :: If true, <tt>application/json</tt> responses will be automatically parsed.
22
- # <tt>:ssl</tt> :: Specify SSL options for the connection.
23
- # <tt>:adapter</tt> :: The name of the Faraday::Adapter::* class to use, e.g. :net_http. To pass arguments
24
- # to the adapter pass an array here, e.g. [:action_dispatch, my_test_session]
25
- # <tt>:raise_errors</tt> :: Default true. When false it will then return the error status and response instead of raising an exception.
26
- def initialize(client_id, client_secret, opts={})
27
- self.options = opts.dup
28
- self.token_method = self.options.delete(:access_token_method) || :post
29
- adapter = self.options.delete(:adapter)
30
- ssl_opts = self.options.delete(:ssl) || {}
31
- connection_opts = ssl_opts ? {:ssl => ssl_opts} : {}
32
- self.id = client_id
33
- self.secret = client_secret
34
- self.site = self.options.delete(:site) if self.options[:site]
35
- self.connection = Faraday::Connection.new(site, connection_opts)
36
- self.json = self.options.delete(:parse_json)
37
- self.raise_errors = !(self.options.delete(:raise_errors) == false)
42
+ # @param [String] the OAuth2 provider site host
43
+ def site=(value)
44
+ @connection = nil
45
+ @site = value
46
+ end
38
47
 
39
- if adapter && adapter != :test
40
- connection.build do |b|
41
- b.adapter(*[adapter].flatten)
42
- end
48
+ # The Faraday connection object
49
+ def connection
50
+ @connection ||= begin
51
+ conn = Faraday.new(site, options[:connection_opts])
52
+ conn.build do |b|
53
+ options[:connection_build].call(b)
54
+ end if options[:connection_build]
55
+ conn
43
56
  end
44
57
  end
45
58
 
59
+ # The authorize endpoint URL of the OAuth2 provider
60
+ #
61
+ # @param [Hash] params additional query parameters
46
62
  def authorize_url(params=nil)
47
- path = options[:authorize_url] || options[:authorize_path] || "/oauth/authorize"
48
- connection.build_url(path, params).to_s
63
+ connection.build_url(options[:authorize_url], params).to_s
49
64
  end
50
65
 
51
- def access_token_url(params=nil)
52
- path = options[:access_token_url] || options[:access_token_path] || "/oauth/access_token"
53
- connection.build_url(path, params).to_s
66
+ # The token endpoint URL of the OAuth2 provider
67
+ #
68
+ # @param [Hash] params additional query parameters
69
+ def token_url(params=nil)
70
+ connection.build_url(options[:token_url], params).to_s
54
71
  end
55
72
 
56
73
  # Makes a request relative to the specified site root.
57
- def request(verb, url, params={}, headers={})
58
- if (verb == :get) || (verb == :delete)
59
- resp = connection.run_request(verb, url, nil, headers) do |req|
60
- req.params.update(params)
61
- end
62
- else
63
- resp = connection.run_request(verb, url, params, headers)
74
+ #
75
+ # @param [Symbol] verb one of :get, :post, :put, :delete
76
+ # @param [String] url URL path of request
77
+ # @param [Hash] opts the options to make the request with
78
+ # @option opts [Hash] :params additional query parameters for the URL of the request
79
+ # @option opts [Hash, String] :body the body of the request
80
+ # @option opts [Hash] :headers http request headers
81
+ # @option opts [Boolean] :raise_errors whether or not to raise an OAuth2::Error on 400+ status
82
+ # code response for this request. Will default to client option
83
+ # @option opts [Symbol] :parse @see Response::initialize
84
+ # @yield [req] The Faraday request
85
+ def request(verb, url, opts={})
86
+ url = self.connection.build_url(url, opts[:params]).to_s
87
+
88
+ response = connection.run_request(verb, url, opts[:body], opts[:headers]) do |req|
89
+ yield(req) if block_given?
64
90
  end
91
+ response = Response.new(response, :parse => opts[:parse])
65
92
 
66
- if raise_errors
67
- case resp.status
68
- when 200...299
69
- return response_for(resp)
70
- when 302
71
- return request(verb, resp.headers['location'], params, headers)
72
- when 401
73
- e = OAuth2::AccessDenied.new("Received HTTP 401 during request.")
74
- e.response = resp
75
- raise e
76
- when 409
77
- e = OAuth2::Conflict.new("Received HTTP 409 during request.")
78
- e.response = resp
79
- raise e
80
- else
81
- e = OAuth2::HTTPError.new("Received HTTP #{resp.status} during request.")
82
- e.response = resp
83
- raise e
93
+ case response.status
94
+ when 200..299
95
+ response
96
+ when 300..399
97
+ opts[:redirect_count] ||= 0
98
+ opts[:redirect_count] += 1
99
+ return response if opts[:redirect_count] > options[:max_redirects]
100
+ if response.status == 303
101
+ verb = :get
102
+ opts.delete(:body)
84
103
  end
104
+ request(verb, response.headers['location'], opts)
105
+ when 400..599
106
+ e = Error.new(response)
107
+ raise e if opts[:raise_errors] || options[:raise_errors]
108
+ response.error = e
109
+ response
85
110
  else
86
- response_for resp
111
+ raise Error.new(response), "Unhandled status code value of #{response.status}"
87
112
  end
88
113
  end
89
114
 
90
- def json?; !!@json end
91
-
92
- def web_server; OAuth2::Strategy::WebServer.new(self) end
93
- def password; OAuth2::Strategy::Password.new(self) end
94
-
95
- private
96
-
97
- def response_for(resp)
98
- if json?
99
- return ResponseObject.from(resp)
115
+ # Initializes an AccessToken by making a request to the token endpoint
116
+ #
117
+ # @param [Hash] params a Hash of params for the token endpoint
118
+ # @return [AccessToken] the initalized AccessToken
119
+ def get_token(params)
120
+ opts = {:raise_errors => true, :parse => params.delete(:parse)}
121
+ if options[:token_method] == :post
122
+ opts[:body] = params
123
+ opts[:headers] = {'Content-Type' => 'application/x-www-form-urlencoded'}
100
124
  else
101
- return ResponseString.new(resp)
125
+ opts[:params] = params
102
126
  end
127
+ response = request(options[:token_method], token_url, opts)
128
+ raise Error.new(response) unless response.parsed.is_a?(Hash) && response.parsed['access_token']
129
+ AccessToken.from_hash(self, response.parsed)
130
+ end
131
+
132
+ # The Authorization Code strategy
133
+ #
134
+ # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.1
135
+ def auth_code
136
+ @auth_code ||= OAuth2::Strategy::AuthCode.new(self)
137
+ end
138
+
139
+ # The Resource Owner Password Credentials strategy
140
+ #
141
+ # @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4.3
142
+ def password
143
+ @password ||= OAuth2::Strategy::Password.new(self)
103
144
  end
104
145
  end
105
146
  end