oauth2 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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