oauth2_provider_engine 0.0.1
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/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +40 -0
- data/app/assets/javascripts/oauth2_provider/application.js +52 -0
- data/app/assets/javascripts/oauth2_provider/highcharts.js +162 -0
- data/app/assets/javascripts/oauth2_provider/jquery.tagsinput.js +218 -0
- data/app/assets/stylesheets/oauth2_provider/gh-buttons.css +388 -0
- data/app/assets/stylesheets/oauth2_provider/gh-icons.png +0 -0
- data/app/assets/stylesheets/oauth2_provider/jquery.tagsinput.css +6 -0
- data/app/assets/stylesheets/oauth2_provider/reset.css +2 -0
- data/app/assets/stylesheets/oauth2_provider/template.css +52 -0
- data/app/controllers/oauth2_provider/accesses_controller.rb +39 -0
- data/app/controllers/oauth2_provider/application_controller.rb +17 -0
- data/app/controllers/oauth2_provider/authorize_controller.rb +141 -0
- data/app/controllers/oauth2_provider/clients_controller.rb +85 -0
- data/app/controllers/oauth2_provider/scopes_controller.rb +63 -0
- data/app/controllers/oauth2_provider/token_controller.rb +187 -0
- data/app/helpers/clients_helper.rb +5 -0
- data/app/helpers/oauth2_provider/application_helper.rb +4 -0
- data/app/models/oauth2_provider/client.rb +129 -0
- data/app/models/oauth2_provider/document.rb +15 -0
- data/app/models/oauth2_provider/oauth_access.rb +80 -0
- data/app/models/oauth2_provider/oauth_authorization.rb +70 -0
- data/app/models/oauth2_provider/oauth_daily_request.rb +54 -0
- data/app/models/oauth2_provider/oauth_refresh_token.rb +20 -0
- data/app/models/oauth2_provider/oauth_token.rb +78 -0
- data/app/models/oauth2_provider/scope.rb +39 -0
- data/app/views/layouts/oauth2_provider/application.html.erb +62 -0
- data/app/views/oauth2_provider/accesses/index.html.erb +25 -0
- data/app/views/oauth2_provider/accesses/show.html.erb +35 -0
- data/app/views/oauth2_provider/clients/_form.html.erb +50 -0
- data/app/views/oauth2_provider/clients/edit.html.erb +9 -0
- data/app/views/oauth2_provider/clients/index.html.erb +43 -0
- data/app/views/oauth2_provider/clients/new.html.erb +8 -0
- data/app/views/oauth2_provider/clients/show.html.erb +49 -0
- data/app/views/oauth2_provider/scopes/_form.html.erb +35 -0
- data/app/views/oauth2_provider/scopes/edit.html.erb +8 -0
- data/app/views/oauth2_provider/scopes/index.html.erb +27 -0
- data/app/views/oauth2_provider/scopes/new.html.erb +7 -0
- data/app/views/oauth2_provider/scopes/show.html.erb +19 -0
- data/app/views/shared/authorize.html.erb +34 -0
- data/app/views/shared/token.json.erb +8 -0
- data/config/locales/en.yml +31 -0
- data/config/oauth.yml +4 -0
- data/config/routes.rb +25 -0
- data/lib/oauth2_provider.rb +38 -0
- data/lib/oauth2_provider/controller_mixin.rb +53 -0
- data/lib/oauth2_provider/engine.rb +4 -0
- data/lib/oauth2_provider_engine.rb +1 -0
- data/lib/oauth2_provider_engine/version.rb +3 -0
- data/test/dummy/CHANGELOG.rdoc +67 -0
- data/test/dummy/Gemfile +53 -0
- data/test/dummy/Gemfile.lock +254 -0
- data/test/dummy/README.rdoc +522 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/VERSION +1 -0
- data/test/dummy/app/assets/stylesheets/reset.css +2 -0
- data/test/dummy/app/assets/stylesheets/template.css +52 -0
- data/test/dummy/app/controllers/application_controller.rb +52 -0
- data/test/dummy/app/controllers/pastas_controller.rb +23 -0
- data/test/dummy/app/controllers/pizzas_controller.rb +23 -0
- data/test/dummy/app/controllers/sessions_controller.rb +26 -0
- data/test/dummy/app/controllers/users_controller.rb +59 -0
- data/test/dummy/app/models/user.rb +50 -0
- data/test/dummy/app/views/layouts/application.html.erb +65 -0
- data/test/dummy/app/views/sessions/new.html.erb +25 -0
- data/test/dummy/app/views/shared/403.json.erb +4 -0
- data/test/dummy/app/views/shared/404.json.erb +6 -0
- data/test/dummy/app/views/shared/422.json.erb +5 -0
- data/test/dummy/app/views/shared/500.json.erb +4 -0
- data/test/dummy/app/views/shared/html/404.html.erb +0 -0
- data/test/dummy/app/views/shared/html/422.html.erb +0 -0
- data/test/dummy/app/views/users/_form.html.erb +27 -0
- data/test/dummy/app/views/users/edit.html.erb +8 -0
- data/test/dummy/app/views/users/index.html.erb +20 -0
- data/test/dummy/app/views/users/new.html.erb +46 -0
- data/test/dummy/app/views/users/show.html.erb +15 -0
- data/test/dummy/app/views/users/show.json.erb +6 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +57 -0
- data/test/dummy/config/boot.rb +13 -0
- data/test/dummy/config/cucumber.yml +8 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +32 -0
- data/test/dummy/config/environments/production.rb +58 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/test.rb +3 -0
- data/test/dummy/config/locales/en.yml +1 -0
- data/test/dummy/config/mongoid.yml +20 -0
- data/test/dummy/config/routes.rb +22 -0
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/doc/README_FOR_APP +2 -0
- data/test/dummy/lib/tasks/cucumber.rake +53 -0
- data/test/dummy/lib/tasks/watchr.rake +5 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +4 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/robots.txt +5 -0
- data/test/dummy/script/cucumber +10 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/spec/acceptance/acceptance_helper.rb +5 -0
- data/test/dummy/spec/acceptance/accesses_controller_spec.rb +77 -0
- data/test/dummy/spec/acceptance/clients_controller_spec.rb +218 -0
- data/test/dummy/spec/acceptance/oauth_authorize_controller_spec.rb +241 -0
- data/test/dummy/spec/acceptance/oauth_token_controller_spec.rb +196 -0
- data/test/dummy/spec/acceptance/resource_controller_spec.rb +143 -0
- data/test/dummy/spec/acceptance/scopes_controller_spec.rb +227 -0
- data/test/dummy/spec/acceptance/support/helpers.rb +81 -0
- data/test/dummy/spec/acceptance/support/paths.rb +9 -0
- data/test/dummy/spec/acceptance/support/view_helpers.rb +52 -0
- data/test/dummy/spec/acceptance/users_controller_spec.rb +198 -0
- data/test/dummy/spec/extras/scope_spec.rb +105 -0
- data/test/dummy/spec/factories/oauth.rb +106 -0
- data/test/dummy/spec/models/oauth/client_spec.rb +123 -0
- data/test/dummy/spec/models/oauth/oauth_access_spec.rb +48 -0
- data/test/dummy/spec/models/oauth/oauth_authorization_spec.rb +50 -0
- data/test/dummy/spec/models/oauth/oauth_daily_request_spec.rb +14 -0
- data/test/dummy/spec/models/oauth/oauth_refresh_token_spec.rb +11 -0
- data/test/dummy/spec/models/oauth/oauth_token_spec.rb +55 -0
- data/test/dummy/spec/models/scope_spec.rb +17 -0
- data/test/dummy/spec/spec_helper.rb +39 -0
- data/test/dummy/spec/support/settings_helper.rb +28 -0
- data/test/dummy/test/initializers/capybara_headers_hack.rb +23 -0
- data/test/oauth2_provider_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- metadata +387 -0
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/help-us.png
|
|
2
|
+
|
|
3
|
+
{The Lelylan Team}[http://lelylan.com]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
= Rest OAuth 2.0 Server
|
|
7
|
+
|
|
8
|
+
<b>Rest OAuth 2.0 Server</b> is a project that easily allows the generation of an OAuth 2.0 Server following the {draft 13}[http://tools.ietf.org/html/draft-ietf-oauth-v2-13]
|
|
9
|
+
of the OAuth 2.0 protocol with {bearer tokens}[http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-02]. The spec
|
|
10
|
+
is close to settling down, and we intend to update our code to match the final OAuth 2.0 and bearer token standards.
|
|
11
|
+
OAuth has often been described as a "valet key for the web." It lets applications ask users for access to just the
|
|
12
|
+
data they need and no more, giving them the ability to enable and disable the accesses whenever they want, most of
|
|
13
|
+
the time without sharing their secret credentials.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
= Installation
|
|
17
|
+
|
|
18
|
+
For the Rest OAuth 2.0 Server to work you need to have
|
|
19
|
+
|
|
20
|
+
* {Ruby 1.9.2}[www.ruby-lang.org/en/] (use rvm[http://screencasts.org/episodes/how-to-use-rvm?utm_source=rubyweekly&utm_medium=email] to manage versions).
|
|
21
|
+
* {MongoDB}[http://www.mongodb.org/].
|
|
22
|
+
|
|
23
|
+
To install the project run the following commands (remember to run <tt>$ mongod</tt> before)
|
|
24
|
+
|
|
25
|
+
$ git clone git@github.com:Lelylan/rest-oauth2-server.git
|
|
26
|
+
$ cd rest-oauth2-server
|
|
27
|
+
$ bundle install
|
|
28
|
+
$ rake spec
|
|
29
|
+
$ rails s
|
|
30
|
+
|
|
31
|
+
If everything works fine, you have your OAuth 2.0 Server up and running! We are also working at a gem and a
|
|
32
|
+
generator to easily integrate the Rest OAuth 2.0 server into your project, so stay tuned.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
== Admin user definition
|
|
36
|
+
|
|
37
|
+
When accessing the application for the first time, click to sign up. A message will ask you to create the first
|
|
38
|
+
administrator user as no one have been found.
|
|
39
|
+
|
|
40
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/first-user-creation.png
|
|
41
|
+
|
|
42
|
+
Register, log in and access the admin dashboard where you will find the following sections.
|
|
43
|
+
|
|
44
|
+
* <b>Users</b>: list with all registered users.
|
|
45
|
+
* <b>Scopes</b>: authorization scopes administration.
|
|
46
|
+
* <b>Accesses</b>: clients that access the user's data.
|
|
47
|
+
* <b>Clients</b>: registered clients (third party application)
|
|
48
|
+
|
|
49
|
+
While the Users and Scopes sections are visible only to the admin, Accesses and Clients are available to every
|
|
50
|
+
registered user, also the ones that will grant access for their resources. To better understand what you can do
|
|
51
|
+
explore the Dashboard and read the following sections.
|
|
52
|
+
|
|
53
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/admin-dashboard.png
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
== Scopes explained
|
|
57
|
+
|
|
58
|
+
In a short way, scopes tell you <b>what can and can't be accessed</b>. The Rest OAuth 2.0 Server ships with a
|
|
59
|
+
flexible and powerful scope system which can be dynamically built.
|
|
60
|
+
|
|
61
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/scopes.png
|
|
62
|
+
|
|
63
|
+
To create a new scope click <b>Create a new scope</b> and you will get a simple form with two fields
|
|
64
|
+
|
|
65
|
+
* <b>Name</b>: unique alphanumeric key that identify a scope.
|
|
66
|
+
* <b>Values</b>: list of space separated alphanumeric strings, each of one refers to an action (built following the convention <b>{controller name}/{action name}</b>) or to an existing scope name.
|
|
67
|
+
|
|
68
|
+
Going a bit deeper you can define the accessible actions in two ways.
|
|
69
|
+
|
|
70
|
+
=== Action specific values
|
|
71
|
+
|
|
72
|
+
You can specify *any* action present in your rails app. For example if you want to allow the access to the action
|
|
73
|
+
create in the controller pizzas you just add the string "pizzas/create". Here you can see an example on defining the
|
|
74
|
+
access to all RESTful actions in a sample pizzas controller.
|
|
75
|
+
|
|
76
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/pizzas-scope.png
|
|
77
|
+
|
|
78
|
+
=== Scope name values
|
|
79
|
+
|
|
80
|
+
You can specify any group of actions adding a name scope. For example if the scope pizzas allows the access to all
|
|
81
|
+
actions in the pizzas controller and the scope pastas allow the access to all actions in pastas controller, then the
|
|
82
|
+
"all" "cope could have as values the list "pizzas pastas"
|
|
83
|
+
|
|
84
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/all-scope.png
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
== Protect your resources
|
|
88
|
+
|
|
89
|
+
After scopes are defined there is one more step. You need to protect the actions you want to authorize. To do thi
|
|
90
|
+
add the filter <tt>oauth_authorized</tt> in any controller you want to protect.
|
|
91
|
+
|
|
92
|
+
class PizzasController < ApplicationController
|
|
93
|
+
before_filter :oauth_authorized
|
|
94
|
+
...
|
|
95
|
+
|
|
96
|
+
This filter verify if the client can access the specific action, regarding the scope that has been granted from the user.
|
|
97
|
+
You can also decide to protect all of your resources (they must accept JSON format) by uncommenting <tt>oauth_authorized</tt>
|
|
98
|
+
line in the {ApplicationController}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/controllers/application_controller.rb].
|
|
99
|
+
|
|
100
|
+
Last, you can make some actions public by using the <tt>exclude</tt> option.
|
|
101
|
+
|
|
102
|
+
before_filter :oauth_authorized, except: %w(index, show)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
== Client definition
|
|
106
|
+
|
|
107
|
+
Every registered user can define a client (third party application). To do this access the dashboard and create your first
|
|
108
|
+
client filling these fields.
|
|
109
|
+
|
|
110
|
+
* <b>Name</b>: client name.
|
|
111
|
+
* <b>Siti URI</b>: client web site URI.
|
|
112
|
+
* <b>Redirect URI</b>: client redirect URI, used as callback after the user grant or deny the access.
|
|
113
|
+
* <b>Scope</b>: one or more scope names, separated by spaces (limit the possible accesses a client can have). By default a
|
|
114
|
+
scope named "all" is set as default. For this reason follow the convention to call "all" the scope that give all accesses.
|
|
115
|
+
* <b>Info</b>: additional information.
|
|
116
|
+
|
|
117
|
+
Once the client is create the additional field <b>client uri</b> and <b>secret</b> are generated. You will use these info
|
|
118
|
+
later on, during the authorization flows.
|
|
119
|
+
|
|
120
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/client-show.png
|
|
121
|
+
|
|
122
|
+
If you define a scope named <b>all</b> you can use one more functionality. You can click the button <b>Simulate Authorization</b>
|
|
123
|
+
that you can find in the end of the client detail page, and you will see the authorization page that a user would normally see
|
|
124
|
+
when granting access to a client.
|
|
125
|
+
|
|
126
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/authorization.png
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
=== Block clients
|
|
130
|
+
|
|
131
|
+
The admin can access to all created clients and decide to block any of them, meaning all related access tokens are disabled.
|
|
132
|
+
This is pretty useful in cases where a client is considered "not safe". When a client is blocked every authorization request
|
|
133
|
+
will be disabled, until the admin unblock it.
|
|
134
|
+
|
|
135
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/block-clients.png
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
== Granted Clients (aka accesses)
|
|
139
|
+
|
|
140
|
+
Once users grant the access to their resources, the accesses list is updated. Here a user can see which clients are accessing
|
|
141
|
+
their resources, and with which frequency. One important functionality lies on the possibility for a user to block a specific
|
|
142
|
+
client, whenever it is considered "not safe".
|
|
143
|
+
|
|
144
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/access.png
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
= OAuth 2.0 flows explained
|
|
150
|
+
|
|
151
|
+
Today Rest OAuth 2.0 Server supports three flows of OAuth 2.0
|
|
152
|
+
* The server-side flow for web applications with servers that can securely store persistent information ({Authorization Code Flow}[http://tools.ietf.org/html/draft-ietf-oauth-v2-13#section-4.1])
|
|
153
|
+
* The client-side flow for JavaScript applications running in a browser ({Implicit Grant Flow}[http://tools.ietf.org/html/draft-ietf-oauth-v2-13#section-4.2])
|
|
154
|
+
* The native application flow for desktop and mobile applications ({Resource Owner Password Credentials Flow}[http://tools.ietf.org/html/draft-ietf-oauth-v2-13#section-4.3])
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
== OAuth 2.0 for server-side web applications
|
|
158
|
+
|
|
159
|
+
This flow is meant for web applications with servers that can keep secrets and maintain state.
|
|
160
|
+
|
|
161
|
+
The server-side flow has two parts. In the first part, your application asks the user for permission to access
|
|
162
|
+
their data. If the user approves, instead of sending an access token directly as in the client-side flow, the
|
|
163
|
+
Rest OAuth 2.0 Server will send to the client an authorization code. In the second part, the client will POST
|
|
164
|
+
that code along with its client secret to the Rest OAuth 2.0 Server in order to get the access token.
|
|
165
|
+
|
|
166
|
+
=== Getting an access token
|
|
167
|
+
|
|
168
|
+
This flow begins by sending the user to the authorization endpoint <tt>/oauth/authorization</tt>
|
|
169
|
+
with the following query parameters
|
|
170
|
+
|
|
171
|
+
* <b>response_type</b> (REQUIRED): always use "code" as response type
|
|
172
|
+
* <b>client_id</b> (REQUIRED): client identifier (the URI of the client model)
|
|
173
|
+
* <b>redirect_uri</b> (REQUIRED): callback URI to the client application
|
|
174
|
+
* <b>scope</b> (REQUIRED): privileges given to the client
|
|
175
|
+
* <b>state</b> (OPTIONAL): opaque value used by the client to maintain state between the request and callback
|
|
176
|
+
|
|
177
|
+
Here's an example URL for a hypothetical app called "Example App" running on https://www.example.com
|
|
178
|
+
|
|
179
|
+
http://localhost:3000/oauth/authorization?
|
|
180
|
+
response_type=code&
|
|
181
|
+
client_id=http://localhost:3000/clients/a918F2fs3&
|
|
182
|
+
redirect_uri=httsp://www.example.com/callback&
|
|
183
|
+
scope=write&
|
|
184
|
+
state=2af5D3vds
|
|
185
|
+
|
|
186
|
+
And this is what you should see.
|
|
187
|
+
|
|
188
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/authorization.png
|
|
189
|
+
|
|
190
|
+
After the user approves access or chooses not to, we'll redirect to the <tt>redirect_uri</tt> you pass us. If the
|
|
191
|
+
user denies access, an error code is appended:
|
|
192
|
+
|
|
193
|
+
https://example.com/callback?error=access_denied&state=2af5D3vds
|
|
194
|
+
|
|
195
|
+
If the user approves access will be appended an authorization code in the query string of the URL:
|
|
196
|
+
|
|
197
|
+
https://example.com/callback?code=g2VDXwrT0S6iZeUeYQBYi2stxRy&state=2af5D3vds
|
|
198
|
+
|
|
199
|
+
Now, the client reached through the <tt>redirect_uri</tt> should swap that authorization code for an access token by POSTing
|
|
200
|
+
it along the following params to the token endpoint <tt>/oauth/token</tt> using the JSON format.
|
|
201
|
+
|
|
202
|
+
* <b>code</b> (REQUIRED): authorization code (from the previous step)
|
|
203
|
+
* <b>grant_type</b> (REQUIRED): always use "authorization_code" as grant type
|
|
204
|
+
* <b>client_id</b> (REQUIRED): client identifier (in our case is the uri field of the client)
|
|
205
|
+
* <b>client_secred</b> (REQUIRED): client secret code
|
|
206
|
+
|
|
207
|
+
Using curl the request might look like:
|
|
208
|
+
|
|
209
|
+
curl -i http://localhost:3000/oauth/token \
|
|
210
|
+
-H "Accept: application/json" \
|
|
211
|
+
-X POST -d '{
|
|
212
|
+
"code": "g2VDXwrT0S6iZeUeYQBYi2stxRy", \
|
|
213
|
+
"grant_type": "authorization_code", \
|
|
214
|
+
"client_id": "http://localhost:30000/clients/a918F2fs3", \
|
|
215
|
+
"client_secret": "a34a7afe4731e745de9d61iZeUeY" \
|
|
216
|
+
}'
|
|
217
|
+
|
|
218
|
+
The response is a JSON Object containing the access token:
|
|
219
|
+
|
|
220
|
+
{
|
|
221
|
+
"access_token": "SlAV32hkKG",
|
|
222
|
+
"expires_in": 1800,
|
|
223
|
+
"refresh_token": "Da8i1930LSj"
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
=== Getting additional access tokens
|
|
227
|
+
|
|
228
|
+
When your access token expires, Rest OAuth 2.0 Server API endpoints will respond with HTTP 401 Unauthorized. At any time,
|
|
229
|
+
you can use the token endpoint with your refresh token with the following query parameters
|
|
230
|
+
|
|
231
|
+
* <b>grant_type</b> (REQUIRED): always use "refresh_token" as grant type
|
|
232
|
+
* <b>client_id</b> (REQUIRED): client identifier (in our case is the uri field of the client)
|
|
233
|
+
* <b>client_secred</b> (REQUIRED): client secret code
|
|
234
|
+
* <b>refresh_token</b> (REQUIRED): refresh token previusly received
|
|
235
|
+
|
|
236
|
+
Using curl the request might look like:
|
|
237
|
+
|
|
238
|
+
curl -i http://localhost:3000/oauth/token \
|
|
239
|
+
-H "Accept: application/json" \
|
|
240
|
+
-X POST -d '{
|
|
241
|
+
"grant_type": "refresh_token", \
|
|
242
|
+
"refresh_token": "Da8i1930LSj", \
|
|
243
|
+
"client_id": "http://localhost:30000/clients/a918F2fs3", \
|
|
244
|
+
"client_secret": "a34a7afe4731e745de9d61iZeUeY" \
|
|
245
|
+
}'
|
|
246
|
+
|
|
247
|
+
The response is a JSON Object containing the new access token.
|
|
248
|
+
|
|
249
|
+
{
|
|
250
|
+
"access_token": "AlYZ892hsKs",
|
|
251
|
+
"expires_in": 1800,
|
|
252
|
+
"refresh_token": "Da8i1930LSj"
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
=== Going deep
|
|
257
|
+
|
|
258
|
+
If you are curious and you want to find more check the {acceptance}[https://github.com/Lelylan/rest-oauth2-server/blob/master/spec/acceptance/oauth/oauth_authorize_controller_spec.rb]
|
|
259
|
+
{tests}[https://github.com/Lelylan/rest-oauth2-server/blob/master/spec/acceptance/oauth/oauth_token_controller_spec.rb]
|
|
260
|
+
in the <b>authorization token flow</b> and <b>refresh token</b> context.
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
== OAuth 2.0 for client-side web applications
|
|
265
|
+
|
|
266
|
+
This flow is meant for JavaScript-based web applications that can't maintain state over time (it includes also ActionScript
|
|
267
|
+
and SilverLight).
|
|
268
|
+
|
|
269
|
+
=== Getting a user's permission
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
This flow begins by sending the user to the authorization endpoint <tt>/oauth/authorization</tt>
|
|
273
|
+
with the following query parameters
|
|
274
|
+
|
|
275
|
+
* <b>response_type</b> (REQUIRED): always use "token" as response type
|
|
276
|
+
* <b>client_id</b> (REQUIRED): client identifier (the uri of the client model)
|
|
277
|
+
* <b>redirect_uri</b> (REQUIRED): callback URI to the client application
|
|
278
|
+
* <b>scope</b> (REQUIRED): privileges given to the client
|
|
279
|
+
* <b>state</b> (OPTIONAL): opaque value used by the client to maintain state between the request and callback
|
|
280
|
+
|
|
281
|
+
Here's an example URL for a hypothetical app called "Example App" running on https://www.example.com
|
|
282
|
+
|
|
283
|
+
http://localhost:3000/oauth/authorization?
|
|
284
|
+
response_type=token&
|
|
285
|
+
client_id=http://localhost:3000/clients/a918F2fs3&
|
|
286
|
+
redirect_uri=httsp://www.example.com/callback&
|
|
287
|
+
scope=write&
|
|
288
|
+
state=2af5D3vds
|
|
289
|
+
|
|
290
|
+
And this is what you should see.
|
|
291
|
+
|
|
292
|
+
http://github.com/Lelylan/rest-oauth2-server/raw/development/public/images/screenshots/authorization.png
|
|
293
|
+
|
|
294
|
+
After the user approves access or chooses not to, we'll redirect to the <tt>redirect_uri</tt> you pass. If the
|
|
295
|
+
user denies access, an error code is appended:
|
|
296
|
+
|
|
297
|
+
https://example.com/callback#error=access_denied&state=2af5D3vds
|
|
298
|
+
|
|
299
|
+
If the user approves will be appended an access token in the hash fragment of the UR:
|
|
300
|
+
|
|
301
|
+
https://example.com/callback#token=g2VDXwrT0S6iZeUeYQBYi2stxRy&expires_in=1800&state=2af5D3vds
|
|
302
|
+
|
|
303
|
+
JavaScript running on that page can grab that access token from the <tt>window.location.hash</tt> and either store it in a
|
|
304
|
+
cookie or POST it to a server. Note that the token is added to the {fragment URI}[http://en.wikipedia.org/wiki/Fragment_identifier].
|
|
305
|
+
This is done because the fragment URI can not be read from server side, but only from client-based applications.
|
|
306
|
+
|
|
307
|
+
=== Getting additional access tokens
|
|
308
|
+
|
|
309
|
+
When your access token expires, our API endpoints will respond with HTTP 401 Unauthorized. At any time, you can send
|
|
310
|
+
your user to the same authorization endpoint you used in the previous step. If the user has already authorized your
|
|
311
|
+
application for the scopes you're requesting, Rest OAuth Server won't show the OAuth dialog and will immediately redirect
|
|
312
|
+
to the <tt>redirect_uri</tt> you pass us with a new access token.
|
|
313
|
+
|
|
314
|
+
=== Going deep
|
|
315
|
+
|
|
316
|
+
If you are curious and you want to find more check the {acceptance tests}[https://github.com/Lelylan/rest-oauth2-server/blob/master/spec/acceptance/oauth/oauth_authorize_controller_spec.rb]
|
|
317
|
+
in the <b>implicit token flow</b> and <b>refresh implicit token flow</b> context.
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
== OAuth 2.0 for native applications
|
|
322
|
+
|
|
323
|
+
This flow is meant for mobile, and desktop installed applications that want access to user data (native apps).
|
|
324
|
+
|
|
325
|
+
This flow is suitable in cases where the resource owner has a trust relationship with the client, such as its computer operating
|
|
326
|
+
system or a highly privileged application. The authorization server should take special care when enabling the grant type, and
|
|
327
|
+
<b>only when other flows are not viable</b>, because username and password are shared with the client.
|
|
328
|
+
|
|
329
|
+
=== Getting an access token
|
|
330
|
+
|
|
331
|
+
The client should POST to the token endpoint <tt>/oauth/token</tt> along with the following params
|
|
332
|
+
using the JSON format:
|
|
333
|
+
|
|
334
|
+
* <b>grant_type</b> (REQUIRED): always use "password" as grant type
|
|
335
|
+
* <b>username</b> (REQUIRED): resource owner email address
|
|
336
|
+
* <b>password</b> (REQUIRED): resource owner password
|
|
337
|
+
* <b>client_id</b> (REQUIRED): client identifier (the uri of the client model)
|
|
338
|
+
* <b>redirect_uri</b> (REQUIRED): callback URI to the client application
|
|
339
|
+
* <b>scope</b> (REQUIRED): privileges given to the client
|
|
340
|
+
|
|
341
|
+
Using curl the request might look like:
|
|
342
|
+
|
|
343
|
+
curl -i http://localhost:3000/oauth/token \
|
|
344
|
+
-H "Accept: application/json" \
|
|
345
|
+
-X POST -d '{
|
|
346
|
+
"grant_type": "password", \
|
|
347
|
+
"client_id": "http://localhost:3000/clients/a918F2fs3", \
|
|
348
|
+
"client_secret": "a34a7afe4731e745de9d61iZeUeY", \
|
|
349
|
+
"username": "alice@example.com", \
|
|
350
|
+
"password": "example", \
|
|
351
|
+
"scope": "write" \
|
|
352
|
+
}'
|
|
353
|
+
|
|
354
|
+
The response is a JSON Object containing the access token:
|
|
355
|
+
|
|
356
|
+
{
|
|
357
|
+
"access_token": "AlYZ892hsKs",
|
|
358
|
+
"expires_in": 1800,
|
|
359
|
+
"refresh_token": "Da8i1930LSj"
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
=== Getting additional access tokens
|
|
363
|
+
|
|
364
|
+
When your access token expires, Rest OAuth 2.0 Server API endpoints will respond with HTTP 401 Unauthorized. At any time,
|
|
365
|
+
you can use the token endpoint with your refresh token with the following query parameters
|
|
366
|
+
|
|
367
|
+
* <b>grant_type</b> (REQUIRED): always use "refresh_token" as grant type
|
|
368
|
+
* <b>client_id</b> (REQUIRED): client identifier (in our case is the uri field of the client)
|
|
369
|
+
* <b>client_secred</b> (REQUIRED): client secret code
|
|
370
|
+
* <b>refresh_token</b> (REQUIRED): refresh token previusly received
|
|
371
|
+
|
|
372
|
+
Using curl the request might look like:
|
|
373
|
+
|
|
374
|
+
curl -i http://localhost:3000/oauth/token \
|
|
375
|
+
-H "Accept: application/json" \
|
|
376
|
+
-X POST -d '{
|
|
377
|
+
"grant_type": "refresh_token", \
|
|
378
|
+
"refresh_token": "Da8i1930LSj", \
|
|
379
|
+
"client_id": "http://localhost:30000/clients/a918F2fs3", \
|
|
380
|
+
"client_secret": "a34a7afe4731e745de9d61iZeUeY" \
|
|
381
|
+
}'
|
|
382
|
+
|
|
383
|
+
The response is a JSON Object containing the new access token.
|
|
384
|
+
|
|
385
|
+
{
|
|
386
|
+
"access_token": "AlYZ892hsKs",
|
|
387
|
+
"expires_in": 1800,
|
|
388
|
+
"refresh_token": "Da8i1930LSj"
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
=== Going deep
|
|
392
|
+
|
|
393
|
+
If you are curious and you want to find more check the {acceptance tests}[https://github.com/Lelylan/rest-oauth2-server/blob/master/spec/acceptance/oauth/oauth_token_controller_spec.rb]
|
|
394
|
+
in the <b>password credentials flow</b> and <b>refresh token</b> context.
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
= How to use Access Token
|
|
399
|
+
|
|
400
|
+
To make API requests on the behalf of a user, pass the OAuth token in the query string, as a header, or as a parameter
|
|
401
|
+
in the request body when making a POST request.
|
|
402
|
+
|
|
403
|
+
Query string example.
|
|
404
|
+
|
|
405
|
+
GET /pizzas?token=AlYZ892hsKs
|
|
406
|
+
|
|
407
|
+
Header example.
|
|
408
|
+
|
|
409
|
+
GET /pizzas
|
|
410
|
+
Authorization: OAuth2 AlYZ892hsKs
|
|
411
|
+
|
|
412
|
+
Request body example.
|
|
413
|
+
|
|
414
|
+
POST /pizzas
|
|
415
|
+
token=AlYZ892hsKs&...
|
|
416
|
+
|
|
417
|
+
Note that all requests must be done using HTTPS.
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
= Miscellaneous
|
|
422
|
+
|
|
423
|
+
== OAuth 2.0 options
|
|
424
|
+
|
|
425
|
+
Rest OAuth 2.0 Server allows you to personalize some options changing {oauth.yml}[https://github.com/Lelylan/rest-oauth2-server/blob/master/config/oauth.yml]
|
|
426
|
+
|
|
427
|
+
* <b>token_expires_in</b>: define the seconds after which the access token expires.
|
|
428
|
+
* <b>authorization_expires_in</b>: define the seconds after which the authorization code expires.
|
|
429
|
+
* <b>secure_random</b>: define the lenght of tokens, code and secret keys.
|
|
430
|
+
* <b>scope_separator</b>: define the separator used between different scope keys.
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
== OAuth 2.0 Models
|
|
434
|
+
|
|
435
|
+
Rest OAuth 2.0 Server is working on top of 5 models. They are pretty simple so if you want to have more information about
|
|
436
|
+
them, check the source code, which is clearly documented.
|
|
437
|
+
|
|
438
|
+
* {OauthClient}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/client.rb]: represents the credentials of a client application.
|
|
439
|
+
* {OauthToken}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/oauth/oauth_token.rb]: represents the token used to access user's resources.
|
|
440
|
+
* {OauthAuthorizarion}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/oauth/oauth_authorization.rb]: represents the authorization token used to exchange an access token.
|
|
441
|
+
* {OauthAccess}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/oauth/oauth_access.rb]: represents the relation between a client and a user, whenever a user grant an authorization.
|
|
442
|
+
* {OauthDailyRequests}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/oauth/oauth_daily_request.rb]: represents a daily request from the client on behalf of a specific user.
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
== Basic authentication system
|
|
446
|
+
|
|
447
|
+
In addition to the models above there is a basic authentication system
|
|
448
|
+
|
|
449
|
+
* {User}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/models/user.rb]: represents the basic user authentication functionalities
|
|
450
|
+
* {UsersController}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/controllers/users_controller.rb]: represents the user definition
|
|
451
|
+
* {SessionsController}[https://github.com/Lelylan/rest-oauth2-server/blob/master/app/controllers/sessions_controller.rb]: represents the session definition
|
|
452
|
+
|
|
453
|
+
This model is kept simple on purpose, but you can easily change it with the authentication system you prefer like {Authlogic}[https://github.com/binarylogic/authlogic],
|
|
454
|
+
{Devise}[https://github.com/plataformatec/devise] or {Warden}[https://github.com/hassox/warden]. Just remember that your user model <b>must</b>
|
|
455
|
+
define an <tt>uri</tt> field, which is used as identifier on the OAuth 2.0 flows. Any help on integration is appreciated.
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
== Blocking system explained
|
|
459
|
+
|
|
460
|
+
One important feature lie in the ability of to block a client. Rest OAuth 2.0 server enables you two possibilities:
|
|
461
|
+
|
|
462
|
+
* <b>Client block</b> via <tt>client.block!</tt>: used to block a not safe client for all users.
|
|
463
|
+
* <b>User block a client</b> via <tt>access.block!</tt>: used when a user want to revoke any access to his resources to a specific client.
|
|
464
|
+
* <b>User block an access token</b> via <tt>token.block!</tt>: used when a user logout from the client and want to revoke the token access.
|
|
465
|
+
|
|
466
|
+
In the first two cases it is possible to unblock the client using the <tt>unblock!</tt> method.
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
== Testing solutions
|
|
470
|
+
|
|
471
|
+
Tests are made using {Steak}[https://github.com/cavalle/steak], {Capybara}[https://github.com/jnicklas/capybara]
|
|
472
|
+
and {RSpec}[https://github.com/rspec/rspec-rails]. If you want to know more check the tests about {models}[https://github.com/Lelylan/rest-oauth2-server/tree/development/spec/models]
|
|
473
|
+
and {acceptance tests}[https://github.com/Lelylan/rest-oauth2-server/tree/development/spec/acceptance].
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
= Other OAuth2 documentation
|
|
478
|
+
|
|
479
|
+
If the way OAuth2 works is not clear, you can find great documentation on the web.
|
|
480
|
+
|
|
481
|
+
* {Oauth2 Specifications}[http://tools.ietf.org/html/draft-ietf-oauth-v2-13]
|
|
482
|
+
* {Google OAuth2}[http://code.google.com/apis/accounts/docs/OAuth2.html]
|
|
483
|
+
* {Facebook OAuth2}[http://developers.facebook.com/docs/authentication]
|
|
484
|
+
* {Gowalla OAuth2}[http://gowalla.com/api/docs/oauth]
|
|
485
|
+
* {Foursquare OAuth2}[http://developer.foursquare.com/docs/oauth.html]
|
|
486
|
+
* {Instagram OAuth2}[http://instagram.com/developer/auth/]
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
= Other OAuth2 Ruby Implementations
|
|
491
|
+
|
|
492
|
+
* {Flowtown Rack OAuth2 Server}[https://github.com/flowtown/rack-oauth2-server]
|
|
493
|
+
* {Nov Rack OAuth2}[https://github.com/nov/rack-oauth2]
|
|
494
|
+
* {ThoughWorks OAuth2 Provider}[https://github.com/ThoughtWorksStudios/oauth2_provider]
|
|
495
|
+
* {Freerange OAuth2 Provider}[https://github.com/freerange/oauth2-provider/blob/master/lib/oauth2/provider/models/access_token.rb]
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
= Contributing
|
|
500
|
+
|
|
501
|
+
Follow {MongoID guidelines}[http://mongoid.org/docs/contributing.html]
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
= Authors
|
|
505
|
+
|
|
506
|
+
{Andrea Reginato}[mailto:andrea.reginato@gmail.com] &
|
|
507
|
+
{The Lelylan Team}[http://lelylan.com]
|
|
508
|
+
|
|
509
|
+
A special thanks to the OAuth 2.0 specification team, to the Flowtown Rack Oauth2 Server which gave the
|
|
510
|
+
initial ideas of the project and to Google OAuth 2.0 specification for making them so clear to understand.
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
= Changelog
|
|
515
|
+
|
|
516
|
+
See {CHANGELOG}[link:blob/master/CHANGELOG.rdoc]
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
= License
|
|
521
|
+
|
|
522
|
+
Rest OAuth 2.0 Server is available under the MIT license.
|