oauth2-client 1.0.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.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ # uncomment this line if your project needs to run something other than `rake`:
6
+ # # script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'json'
4
+
5
+ gem 'bcrypt-ruby', '~> 3.0.0'
6
+
7
+ gem 'addressable'
8
+
9
+ gem 'rake'
10
+
11
+ gem 'rspec', '~>2.12'
12
+
13
+ gem 'simplecov'
14
+
15
+ gem 'activesupport', '~> 3.2.8'
16
+
17
+ # gem 'mocha', '>=0.12.1', :require => false
@@ -0,0 +1,37 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.8)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ addressable (2.3.2)
8
+ bcrypt-ruby (3.0.1)
9
+ diff-lcs (1.1.3)
10
+ i18n (0.6.1)
11
+ json (1.7.5)
12
+ multi_json (1.3.6)
13
+ rake (0.9.2.2)
14
+ rspec (2.12.0)
15
+ rspec-core (~> 2.12.0)
16
+ rspec-expectations (~> 2.12.0)
17
+ rspec-mocks (~> 2.12.0)
18
+ rspec-core (2.12.2)
19
+ rspec-expectations (2.12.1)
20
+ diff-lcs (~> 1.1.3)
21
+ rspec-mocks (2.12.1)
22
+ simplecov (0.7.1)
23
+ multi_json (~> 1.0)
24
+ simplecov-html (~> 0.7.1)
25
+ simplecov-html (0.7.1)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ activesupport (~> 3.2.8)
32
+ addressable
33
+ bcrypt-ruby (~> 3.0.0)
34
+ json
35
+ rake
36
+ rspec (~> 2.12)
37
+ simplecov
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012, Kevin Mutyaba
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.
@@ -0,0 +1,152 @@
1
+ # OAuth2 Ruby Client
2
+
3
+ [![Build Status](https://secure.travis-ci.org/tiabas/oauth2-client.png?branch=master)][travis]
4
+
5
+ [travis]: http://travis-ci.org/tiabas/oauth2-client
6
+
7
+ A Ruby wrapper for the OAuth 2.0 specification. It is designed with the philosophy that not
8
+ every service that claims to support OAuth 2.0 actually implements it according to the
9
+ [standard]( http://tools.ietf.org/html/rfc6749). This version therefore, affords
10
+ the developer some degree of flexibility in generating the URLs and requests
11
+ needed to authorize an OAuth 2.0 application.
12
+
13
+ For more about the standard, take a look at http://tools.ietf.org/html/rfc6749
14
+
15
+ ## Installation
16
+ Download the library and include the its location in your Gemfile
17
+
18
+ ## Resources
19
+ * [View Source on GitHub][code]
20
+ * [Report Issues on GitHub][issues]
21
+
22
+ [code]: https://github.com/tiabas/oauth2-client
23
+ [issues]: https://github.com/tiabas/oauth2-client/issues
24
+
25
+ ## Usage Examples
26
+
27
+ ```ruby
28
+ require 'oauth2-client'
29
+
30
+ @client = OAuth2::Client.new('https://example.com', 's6BhdRkqt3', '4hJZY88TCBB9q8IpkeualA2lZsUhOSclkkSKw3RXuE')
31
+
32
+ client.authorization_code.authorization_path(:redirect_uri => 'http://localhost/oauth2/cb')
33
+ # => "/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Foauth2%2Fcb"
34
+
35
+ ```
36
+
37
+ ## Authorization Grants
38
+ The client wraps around the creation of any given grant and passing in the parameters defined in the configuration
39
+ file. The supported grants include Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials.
40
+ There is also support for device authentication as described in Google's OAuth 2.0 authentication methods(https://developers.google.com/accounts/docs/OAuth2ForDevices). They are available via the #authorization_code, #implicit, #password, #client_credentials, #refresh_token
41
+ and #device methods on a client object.
42
+
43
+ The #get_token method on the grants does not make any assumptions about the format ofthe response from the OAuth provider. The ideal
44
+ case would be to treat all responses as JSON. However, some services may respond with in XML instead of JSON. The #get_token method
45
+ therefore, returns with an HTTPResponse object.
46
+
47
+ ### Authorization Code
48
+ ```ruby
49
+ auth_url = client.authorization_code.authorization_path(:redirect_uri => 'http://localhost/oauth2/cb')
50
+ # => "/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Foauth2%2Fcb"
51
+
52
+ token_url = client.authorization_code.token_path(
53
+ :code => aXW2c6bYz,
54
+ :redirect_uri => 'http://localhost/oauth2/cb')
55
+ # => "/oauth/token?redirect_uri=http%3A%2F%2Flocalhost%2Foauth%2Fcb&client_secret={client_secret}&grant_type=authorization_code&client_id={client_id}&code=aXW2c6bYz"
56
+ ```
57
+
58
+ ### Implicit Grant
59
+ ```ruby
60
+ auth_url = client.implicit.authorization_path(:redirect_uri => 'http://localhost/oauth2/cb')
61
+ # => "oauth/?redirect_uri=http%3A%2F%2Flocalhost%2Foauth%2Fcb&response_type=token&client_id={client_id}"
62
+ ```
63
+
64
+ ### Password Credentials
65
+ ```ruby
66
+ token = client.password.get_token('username', 'password')
67
+ ```
68
+
69
+ ### Refresh Token
70
+ ```ruby
71
+ token = client.refresh_token.get_token(refresh_token_value, :params => {:scope => 'abc xyz', :state => 'state'})
72
+ ```
73
+
74
+ ### Client Credentials
75
+ ```ruby
76
+ token = client.client_credentials.get_token
77
+ ```
78
+
79
+ ### Device Code
80
+ ```ruby
81
+ auth_url = client.device_code.authorization_path(:scope => 'abc xyz', :state => 'state')
82
+ # => "/oauth/device/code?scope=abc+xyz&state=state&client_id={client_id}"
83
+
84
+ # exchange device authorization code for access token
85
+ token = client.device_code.get_token(device_auth_code)
86
+ ```
87
+
88
+ # Client Examples
89
+ This library comes bundled with two sample implementations of Google and Yammer OAuth clients. These clients are
90
+ meant to showcase the degree of flexibilty that you get when using this library to interact with other OAuth 2.0
91
+ providers.
92
+
93
+ ## Google Client
94
+
95
+ ```ruby
96
+
97
+ google_client = GoogleClient.new(
98
+ 'https://accounts.google.com',
99
+ '827502413694.apps.googleusercontent.com',
100
+ 'a2nQpcUm2Dgq1chWdAvbXGTk',
101
+ {
102
+ :token_path => '/o/oauth2/token',
103
+ :authorize_path => '/o/oauth2/auth',
104
+ :device_path => '/o/oauth2/device/code'
105
+ }
106
+ )
107
+
108
+ ```
109
+
110
+ ### Client-side authorization URL(Implicit grant)
111
+ ```ruby
112
+ auth_url = google_client.webserver_authorization_url(
113
+ :scope => 'https://www.googleapis.com/auth/userinfo.email',
114
+ :state => '/profile',
115
+ :redirect_uri => 'https://oauth2-login-demo.appspot.com/code',
116
+ :approval_prompt => 'force')
117
+ # => https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&state=%2Fprofile&redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Ftoken&approval_prompt=force&response_type=token&client_id=812741506391.apps.googleusercontent.com
118
+ ```
119
+
120
+ ### Server-side authorization URL(Authorization code grant)
121
+ ```ruby
122
+ auth_url = google_client.clientside_authorization_url(
123
+ :scope => 'https://www.googleapis.com/auth/userinfo.email',
124
+ :state => '/profile',
125
+ :redirect_uri => 'http://localhost/oauth/code',
126
+ :approval_prompt => 'force')
127
+ # => https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&state=%2Fprofile&redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Fcode&approval_prompt=force&response_type=code&client_id=812741506391.apps.googleusercontent.com
128
+
129
+ # exchange authorization code for access token. we will get back a Net::HTTPResponse
130
+ response = google_client.exchange_auth_code_for_token(
131
+ :params => {
132
+ :code => '4/dbB0-UD1cvrQg2EuEFtRtHwPEmvR.IrScsjgB5M4VuJJVnL49Cc8QdUjRdAI',
133
+ :redirect_uri => 'http://localhost/oauth/token'
134
+ }
135
+ )
136
+ response.inspect
137
+ # => #<Net::HTTPOK:0x007ff8bc7c1200>
138
+
139
+ response.body
140
+ # => {
141
+ "access_token" : "ya91.AHES8ZS-oCZnc5yHepnsosFjNln9ZKLuioF6FcMRCGUIzA",
142
+ "token_type" : "Bearer",
143
+ "expires_in" : 3600,
144
+ "id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6IjY4ZGM2ZmIxNDQ5OGJmMWRhNjNiMWYyMDA2YmRmMDA2N2Q4MzY",
145
+ "refresh_token" : "6/Ju8uhi9xOctGEyHRzWwHhaYimfxmY0tiJ_qW3qvjWXM"
146
+ }
147
+ ```
148
+
149
+ ## Copyright
150
+ Copyright (c) 2012 Kevin Mutyaba
151
+ See [LICENSE][] for details.
152
+ [license]: https://github.com/tiabas/oauth2-client/blob/master/LICENSE
@@ -0,0 +1,11 @@
1
+ #Rakefile
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.verbose = true
7
+ end
8
+
9
+ desc "Run spec"
10
+ task :default => :spec
11
+ task :test => :spec
data/TODO ADDED
@@ -0,0 +1,10 @@
1
+ TODO:
2
+ - Streamline configuration of client
3
+
4
+ - Add documentation for connection class
5
+
6
+ - Make gem 1.8.7 compatible
7
+
8
+ - Update documentation
9
+
10
+ - Submit to gem library
@@ -0,0 +1,159 @@
1
+ class GoogleClient < OAuth2::Client
2
+
3
+ def normalize_scope(scope, sep=' ')
4
+ unless (scope.is_a?(String) || scope.is_a?(Array))
5
+ raise ArgumentError.new("Expected scope of type String or Array but was: #{scope.class.name}")
6
+ end
7
+ return scope if scope.is_a?(String)
8
+ scope.join(sep)
9
+ end
10
+
11
+ # Generates the Google URL that the user will be redirected to in order to
12
+ # authorize your application
13
+ #
14
+ # @see https://developers.google.com/accounts/docs/OAuth2UserAgent#formingtheurl
15
+ #
16
+ # @params [Hash] additional parameters to be include in URL eg. scope, state, etc
17
+ #
18
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
19
+ # :token_path => '/o/oauth2/token',
20
+ # :authorize_path => '/o/oauth2/auth',
21
+ # :device_path => '/o/oauth2/device/code'
22
+ # })
23
+ # client.clientside_authorization_url({
24
+ # :scope => 'https://www.googleapis.com/auth/userinfo.email',
25
+ # :state => '/profile',
26
+ # :redirect_uri => 'https://oauth2-login-demo.appspot.com/code',
27
+ # :approval_prompt => 'force',
28
+ # })
29
+ # #=>
30
+ def clientside_authorization_url(params={})
31
+ params[:scope] = normalize_scope(params[:scope]) if params[:scope]
32
+ implicit.token_url(params)
33
+ end
34
+
35
+ # Generates the Google URL that the user will be redirected to in order to
36
+ # authorize your application
37
+ #
38
+ # @see https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl
39
+ #
40
+ # @params [Hash] additional parameters to be include in URL eg. scope, state, etc
41
+ #
42
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
43
+ # :token_path => '/o/oauth2/token',
44
+ # :authorize_path => '/o/oauth2/auth',
45
+ # :device_path => '/o/oauth2/device/code'
46
+ # })
47
+ # client.webserver_authorization_url({
48
+ # :scope => 'https://www.googleapis.com/auth/userinfo.email',
49
+ # :state => '/profile',
50
+ # :redirect_uri => 'https://oauth2-login-demo.appspot.com/code',
51
+ # :approval_prompt => 'force',
52
+ # })
53
+ # #=>
54
+ def webserver_authorization_url(params={})
55
+ params[:scope] = normalize_scope(params[:scope]) if params[:scope]
56
+ authorization_code.authorization_url(params)
57
+ end
58
+
59
+ # Generates the Google URL that allows a user to obtain an authorization
60
+ # code for a given device
61
+ #
62
+ # @see https://developers.google.com/accounts/docs/OAuth2ForDevices
63
+ # def device_authorization_url(params={})
64
+ # params[:scope] = normalize_scope(params[:scope]) if params[:scope]
65
+ # device.authorization_url(params)
66
+ # end
67
+
68
+ # Makes a request to google server that will swap your authorization code for an access
69
+ # token
70
+ #
71
+ # @see https://developers.google.com/accounts/docs/OAuth2WebServer#handlingtheresponse
72
+ #
73
+ # @params [Hash] additional parameters to be include in URL eg. scope, state, etc
74
+ #
75
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
76
+ # :token_path => '/o/oauth2/token',
77
+ # :authorize_path => '/o/oauth2/auth',
78
+ # :device_path => '/o/oauth2/device/code'
79
+ # })
80
+ # client.exchange_auth_code_for_token({
81
+ # :scope => 'https://www.googleapis.com/auth/userinfo.email',
82
+ # :state => '/profile',
83
+ # :code => 'G3Y6jU3a',
84
+ # })
85
+ # #=>
86
+ def exchange_auth_code_for_token(opts={})
87
+ unless (opts[:params] && opts[:params][:code])
88
+ raise ArgumentError.new("You must include an authorization code as a parameter")
89
+ end
90
+ code = opts[:params].delete(:code)
91
+ authorization_code.get_token(code, opts)
92
+ end
93
+
94
+ # Makes a request to google server that will generate a new access token given that your
95
+ # application was not deauthorized by the user
96
+ #
97
+ # @see https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh
98
+ #
99
+ # @params [Hash] additional parameters to be include in URL eg. state
100
+ #
101
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
102
+ # :token_path => '/o/oauth2/token',
103
+ # :authorize_path => '/o/oauth2/auth',
104
+ # :device_path => '/o/oauth2/device/code'
105
+ # })
106
+ # client.refresh_access_token({
107
+ # :state => '/profile',
108
+ # :refresh_token => '2YotnFZFEjr1zCsicMWpAA'
109
+ # })
110
+ # #=>
111
+ def refresh_access_token(opts={})
112
+ unless (opts[:params] && opts[:params][:refresh_token])
113
+ raise ArgumentError.new("You must provide a refresh_token as a parameter")
114
+ end
115
+ token = opts[:params].delete(:refresh_token)
116
+ refresh_token.get_token(token, opts)
117
+ end
118
+
119
+ # @see https://developers.google.com/accounts/docs/OAuth2ForDevices#obtainingacode
120
+ #
121
+ # @params [Hash] additional parameters to be include in URL eg. state
122
+ #
123
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
124
+ # :token_path => '/o/oauth2/token',
125
+ # :authorize_path => '/o/oauth2/auth',
126
+ # :device_path => '/o/oauth2/device/code'
127
+ # })
128
+ # client.device_code({
129
+ # :state => '/profile',
130
+ # })
131
+ # #=>
132
+ def get_device_code(opts={})
133
+ opts[:params] ||= {}
134
+ opts[:params][:scope] = normalize_scope(opts[:params][:scope]) if opts[:params][:scope]
135
+ device_code.get_code(opts)
136
+ end
137
+
138
+ # @see https://developers.google.com/accounts/docs/OAuth2ForDevices#obtainingatoken
139
+ #
140
+ # @params [Hash] additional parameters to be include in URL eg. state
141
+ #
142
+ # client = GoogleClient.new('https://accounts.google.com', '827502413694.apps.googleusercontent.com', 'a2nQpcUm2Dgq1chWdAvbXGTk',{
143
+ # :token_path => '/o/oauth2/token',
144
+ # :authorize_path => '/o/oauth2/auth',
145
+ # :device_path => '/o/oauth2/device/code'
146
+ # })
147
+ # client.exchange_device_code_for_token({
148
+ # :state => '/profile',
149
+ # :code => 'G3Y6jU3a',
150
+ # })
151
+ # #=>
152
+ def exchange_device_code_for_token(opts={})
153
+ unless (opts[:params] && opts[:params][:code])
154
+ raise ArgumentError.new("You must include an device code as a parameter")
155
+ end
156
+ code = opts[:params].delete(:code)
157
+ device_code.get_token(code, opts)
158
+ end
159
+ end
@@ -0,0 +1,7 @@
1
+ require 'oauth2/version'
2
+ require 'oauth2/error'
3
+ require 'oauth2/helper'
4
+ require 'oauth2/grant'
5
+ require 'oauth2/client'
6
+ require 'oauth2/connection'
7
+