oauth2-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+