oauth2-provider-jonrowe 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +314 -0
- data/example/README.rdoc +11 -0
- data/example/application.rb +151 -0
- data/example/config.ru +3 -0
- data/example/environment.rb +11 -0
- data/example/models/connection.rb +9 -0
- data/example/models/note.rb +4 -0
- data/example/models/user.rb +6 -0
- data/example/public/style.css +78 -0
- data/example/schema.rb +27 -0
- data/example/views/authorize.erb +28 -0
- data/example/views/create_user.erb +3 -0
- data/example/views/home.erb +25 -0
- data/example/views/layout.erb +25 -0
- data/example/views/login.erb +20 -0
- data/example/views/new_client.erb +25 -0
- data/example/views/new_user.erb +22 -0
- data/example/views/show_client.erb +15 -0
- data/lib/oauth2/model.rb +17 -0
- data/lib/oauth2/model/authorization.rb +113 -0
- data/lib/oauth2/model/client.rb +55 -0
- data/lib/oauth2/model/client_owner.rb +13 -0
- data/lib/oauth2/model/hashing.rb +27 -0
- data/lib/oauth2/model/resource_owner.rb +26 -0
- data/lib/oauth2/model/schema.rb +42 -0
- data/lib/oauth2/provider.rb +117 -0
- data/lib/oauth2/provider/access_token.rb +66 -0
- data/lib/oauth2/provider/authorization.rb +168 -0
- data/lib/oauth2/provider/error.rb +29 -0
- data/lib/oauth2/provider/exchange.rb +212 -0
- data/lib/oauth2/router.rb +60 -0
- data/spec/factories.rb +27 -0
- data/spec/oauth2/model/authorization_spec.rb +216 -0
- data/spec/oauth2/model/client_spec.rb +55 -0
- data/spec/oauth2/model/resource_owner_spec.rb +55 -0
- data/spec/oauth2/provider/access_token_spec.rb +125 -0
- data/spec/oauth2/provider/authorization_spec.rb +323 -0
- data/spec/oauth2/provider/exchange_spec.rb +330 -0
- data/spec/oauth2/provider_spec.rb +531 -0
- data/spec/request_helpers.rb +46 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/test_app/helper.rb +33 -0
- data/spec/test_app/provider/application.rb +61 -0
- data/spec/test_app/provider/views/authorize.erb +19 -0
- metadata +220 -0
data/README.rdoc
ADDED
@@ -0,0 +1,314 @@
|
|
1
|
+
= OAuth2::Provider
|
2
|
+
|
3
|
+
This gem provides a toolkit for adding OAuth2 provider capabilities to a Ruby
|
4
|
+
web app. It handles most of the protocol for you: it is designed to provide
|
5
|
+
a sufficient level of abstraction that it can implement updates to the protocol
|
6
|
+
without affecting your application code at all. All you have to deal with is
|
7
|
+
authenticating your users and letting them grant access to client apps.
|
8
|
+
|
9
|
+
It is also designed to be usable within any web frontend, at least those of
|
10
|
+
Rails and Sinatra. It assumes very little about the request objects in your
|
11
|
+
environment, namely they:
|
12
|
+
|
13
|
+
* respond to <tt>#params</tt> with a <tt>Hash</tt> of request parameters
|
14
|
+
* respond to <tt>#get?</tt> and <tt>#post?</tt>
|
15
|
+
* respond to <tt>#url</tt> with the full URL string of the request
|
16
|
+
* respond to <tt>#env</tt>, returning the HTTP environment <tt>Hash</tt>
|
17
|
+
|
18
|
+
It stores the clients and authorizations using ActiveRecord; the schema is in
|
19
|
+
<tt>lib/oauth2/model/schema.rb</tt>. Run it to update your database to
|
20
|
+
store OAuth data:
|
21
|
+
|
22
|
+
OAuth2::Model::Schema.up
|
23
|
+
|
24
|
+
The current imeplementation is based on draft-10[http://tools.ietf.org/html/draft-ietf-oauth-v2-10].
|
25
|
+
|
26
|
+
|
27
|
+
== Usage
|
28
|
+
|
29
|
+
A basic example is in <tt>example/application.rb</tt>. To implement OAuth, you
|
30
|
+
need to provide four things:
|
31
|
+
|
32
|
+
* Some UI to register client applications
|
33
|
+
* The OAuth request endpoint
|
34
|
+
* A flow for logged-in users to grant access to clients
|
35
|
+
* Resources protected by access tokens
|
36
|
+
|
37
|
+
|
38
|
+
=== Configuration
|
39
|
+
|
40
|
+
<tt>OAuth2::Provider</tt> requires very little configuration. The only thing it
|
41
|
+
needs to know about your app is its name, which is used in the headers for some
|
42
|
+
authentication errors. To load the library, just do this:
|
43
|
+
|
44
|
+
require 'oauth2/provider'
|
45
|
+
OAuth2::Provider.realm = 'My OAuth app'
|
46
|
+
|
47
|
+
You may also need to configure assertion handlers if your application supports
|
48
|
+
third-party access credentials. See 'Using Assertions' below.
|
49
|
+
|
50
|
+
|
51
|
+
=== Registering client applications
|
52
|
+
|
53
|
+
Clients are modelled by the <tt>OAuth2::Model::Client</tt> class, which is an
|
54
|
+
ActiveRecord model. You just need to implement a UI for creating them, for
|
55
|
+
example in a Sinatra app:
|
56
|
+
|
57
|
+
get '/oauth/apps/new' do
|
58
|
+
@client = OAuth2::Model::Client.new
|
59
|
+
erb :new_client
|
60
|
+
end
|
61
|
+
|
62
|
+
post '/oauth/apps' do
|
63
|
+
@client = OAuth2::Model::Client.new(params)
|
64
|
+
@client.save ? erb(:show_client) : erb(:new_client)
|
65
|
+
end
|
66
|
+
|
67
|
+
Client applications must have a <tt>name</tt> and a <tt>redirect_uri</tt>:
|
68
|
+
provide fields for editing these but do not allow the other fields to be edited,
|
69
|
+
since they are the client's access credentials. When you've created the client,
|
70
|
+
you should show its details to the user registering the client: its <tt>name</tt>,
|
71
|
+
<tt>redirect_uri</tt>, <tt>client_id</tt> and <tt>client_secret</tt> (the last
|
72
|
+
two are generated for you). <tt>client_secret</tt> is not stored in plain text
|
73
|
+
so you can only read it when you initially create the client object.
|
74
|
+
|
75
|
+
|
76
|
+
=== OAuth request endpoint
|
77
|
+
|
78
|
+
This is a path that your application exposes in order for clients to communicate
|
79
|
+
with your application. It is also the page that the client will send users to
|
80
|
+
so they can authenticate and grant access. Many requests to this endpoint will
|
81
|
+
be protocol-level requests that do not involve the user, and <tt>OAuth2::Provider</tt>
|
82
|
+
gives you a generic way to handle all that.
|
83
|
+
|
84
|
+
You should use this to get the right response, status code and headers to send to
|
85
|
+
the client. In the event that <tt>OAuth2::Provider</tt> does not provide a response,
|
86
|
+
you should render a page that lets the user begin to authenticate and grant access.
|
87
|
+
|
88
|
+
This endpoint must be accessible via GET and POST. In this example we will expose
|
89
|
+
the OAuth service through the path <tt>/oauth/authorize</tt>. We check if there is
|
90
|
+
a logged-in resource owner and give this to <tt>OAuth::Provider</tt>, since we
|
91
|
+
may be able to immediately redirect if the user has already authorized the client:
|
92
|
+
|
93
|
+
[:get, :post].each do |method|
|
94
|
+
__send__ method, '/oauth/authorize' do
|
95
|
+
@owner = User.find_by_id(session[:user_id])
|
96
|
+
@oauth2 = OAuth2::Provider.parse(@owner, request)
|
97
|
+
|
98
|
+
redirect @oauth2.redirect_uri if @oauth2.redirect?
|
99
|
+
|
100
|
+
headers @oauth2.response_headers
|
101
|
+
status @oauth2.response_status
|
102
|
+
|
103
|
+
@oauth2.response_body || erb(:login)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
There is a set of parameters that you will need to hold on to for when your app
|
108
|
+
needs to redirect back to the client. You could store them in the session, or
|
109
|
+
pass them through forms as the user completes the flow. For example to embed
|
110
|
+
them in the login form, do this:
|
111
|
+
|
112
|
+
<% @oauth2.params.each do |key, value| %>
|
113
|
+
<input type="hidden" name="<%= key %>" value="<%= value %>">
|
114
|
+
<% end %>
|
115
|
+
|
116
|
+
You may also want to use scopes to provide granular access to your domain using
|
117
|
+
<i>scopes</i>. The <tt>@oauth2</tt> object exposes the scopes the client has asked
|
118
|
+
for so you can display them to the user:
|
119
|
+
|
120
|
+
<p>The application <%= @oauth2.client.name %> wants the following permissions:</p>
|
121
|
+
|
122
|
+
<ul>
|
123
|
+
<% @oauth2.scopes.each do |scope| %>
|
124
|
+
<li><%= PERMISSION_UI_STRINGS[scope] %></li>
|
125
|
+
<% end %>
|
126
|
+
</ul>
|
127
|
+
|
128
|
+
You can also use the method <tt>@oauth2.unauthorized_scopes</tt> to get the list
|
129
|
+
of scopes the user has not already granted to the client, in the case where the
|
130
|
+
client already has some authorization. If no prior authorization exists between
|
131
|
+
the user and the client, <tt>@oauth2.unauthorized_scopes</tt> just returns all
|
132
|
+
the scopes the client has asked for.
|
133
|
+
|
134
|
+
|
135
|
+
=== Granting access to clients
|
136
|
+
|
137
|
+
Your application will probably have some concept of a user, or a <i>resource
|
138
|
+
owner</i> in OAuth lingo. Add this mixin to the model that represents your
|
139
|
+
users:
|
140
|
+
|
141
|
+
class User < ActiveRecord::Base
|
142
|
+
include OAuth2::Model::ResourceOwner
|
143
|
+
end
|
144
|
+
|
145
|
+
This just adds a couple of relations and methods to the model to let it interact
|
146
|
+
with the <tt>OAuth2</tt> models.
|
147
|
+
|
148
|
+
Once the user has authenticated you should show them a page to let them grant
|
149
|
+
or deny access to the client application. This is straightforward; let's say
|
150
|
+
the user checks a box before posting a form to indicate their intent:
|
151
|
+
|
152
|
+
post '/oauth/allow' do
|
153
|
+
@user = User.find_by_id(session[:user_id])
|
154
|
+
@auth = OAuth2::Provider::Authorization.new(@user, params)
|
155
|
+
|
156
|
+
if params['allow'] == '1'
|
157
|
+
@auth.grant_access!
|
158
|
+
else
|
159
|
+
@auth.deny_access!
|
160
|
+
end
|
161
|
+
redirect @auth.redirect_uri
|
162
|
+
end
|
163
|
+
|
164
|
+
After granting or denying access, we just redirect back to the client using a
|
165
|
+
URI that <tt>OAuth2::Provider</tt> will provide for you.
|
166
|
+
|
167
|
+
|
168
|
+
=== Using password credentials
|
169
|
+
|
170
|
+
If you like, OAuth lets you use a user's login credentials to authenticate with
|
171
|
+
a provider. In this case the client application must request these credentials
|
172
|
+
directly from the user and then post them to the exchange endpoint. On the
|
173
|
+
provider side you can handle this using the <tt>handle_passwords</tt> and
|
174
|
+
<tt>grant_access!</tt> API methods, for example:
|
175
|
+
|
176
|
+
OAuth2::Provider.handle_passwords do |client, username, password|
|
177
|
+
user = User.find_by_username(username)
|
178
|
+
if user.authenticate?(password)
|
179
|
+
user.grant_access!(client)
|
180
|
+
else
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
The block must return <tt>user.grant_access!(client)</tt> if you want to allow
|
186
|
+
access, otherwise it should return <tt>nil</tt>.
|
187
|
+
|
188
|
+
|
189
|
+
=== Using assertions
|
190
|
+
|
191
|
+
Assertions provide a way to access your OAuth services using user credentials
|
192
|
+
from another service. When using assertions, the user will not authenticate on
|
193
|
+
your web site; the OAuth client will authenticate the user using some other
|
194
|
+
framework and obtain a token, then exchange this token for an access token on
|
195
|
+
your domain.
|
196
|
+
|
197
|
+
For example, a client application may let a user authenticate using Facebook,
|
198
|
+
so the application obtains a Facebook access token from the user. The client
|
199
|
+
would then pass this token to your OAuth endpoint and exchange it for an
|
200
|
+
access token from your site. You will typically create an account in your
|
201
|
+
database to represent this, then have that new account grant access to the
|
202
|
+
client.
|
203
|
+
|
204
|
+
To use assertions, you must tell <tt>OAuth2::Provider</tt> how to handle
|
205
|
+
assertions based on their type. An assertion type must be a valid URI. For
|
206
|
+
the Facebook example we'd do the following. The block yields the <tt>Client</tt>
|
207
|
+
object making the exchange request, and the value of the assertion, which in
|
208
|
+
this example will be a Facebook access token.
|
209
|
+
|
210
|
+
OAuth2::Provider.handle_assertions 'https://graph.facebook.com/me' do |client, assertion|
|
211
|
+
facebook = URI.parse('https://graph.facebook.com/me?access_token=' + assertion)
|
212
|
+
response = Net::HTTP.get_response(facebook)
|
213
|
+
|
214
|
+
user_data = JSON.parse(response.body)
|
215
|
+
account = User.from_facebook_data(user_data)
|
216
|
+
|
217
|
+
account.grant_access!(client)
|
218
|
+
end
|
219
|
+
|
220
|
+
This code should run when your app boots, not during a request handler - think
|
221
|
+
of it as configuration for <tt>OAuth2::Provider</tt>. The framework will invoke
|
222
|
+
it when a client attempts to use assertions with your OAuth endpoint.
|
223
|
+
|
224
|
+
The final call in your handler should be to <tt>grant_access!</tt>; this returns
|
225
|
+
an <tt>Authorization</tt> object that the framework then uses to complete the
|
226
|
+
response to the client. If you want to deny the request for whatever reason, the
|
227
|
+
block must return <tt>nil</tt>. If a client tries to use an assertion type you
|
228
|
+
have no handler for, the client will get an error response.
|
229
|
+
|
230
|
+
|
231
|
+
=== Protecting resources with access tokens
|
232
|
+
|
233
|
+
To protect the user's resources you need to check for access tokens. This is
|
234
|
+
simple, for example a call to get a user's notes:
|
235
|
+
|
236
|
+
get '/user/:username/notes' do
|
237
|
+
user = User.find_by_username(params[:username])
|
238
|
+
token = OAuth2::Provider.access_token(user, ['read_notes'], request)
|
239
|
+
|
240
|
+
headers token.response_headers
|
241
|
+
status token.response_status
|
242
|
+
|
243
|
+
if token.valid?
|
244
|
+
JSON.unparse('notes' => user.notes)
|
245
|
+
else
|
246
|
+
JSON.unparse('error' => 'No notes for you!')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
<tt>OAuth2::Provider.access_token()</tt> takes a <tt>ResourceOwner</tt>, a list
|
251
|
+
of scopes required to access the resource, and a request object. If the token
|
252
|
+
was not granted for the required scopes, has expired or is simply invalid,
|
253
|
+
headers and a status code are set to indicate this to the client. <tt>token.valid?</tt>
|
254
|
+
is the call you should use to determine whether to server the request or not.
|
255
|
+
|
256
|
+
It is also common to provide a dynamic resource for getting some basic data
|
257
|
+
about a user by supplying their access token. This can be done by passing
|
258
|
+
<tt>nil</tt> as the resource owner:
|
259
|
+
|
260
|
+
get '/me' do
|
261
|
+
token = OAuth2::Provider.access_token(nil, [], request)
|
262
|
+
if token.valid?
|
263
|
+
JSON.unparse('username' => token.owner.username)
|
264
|
+
else
|
265
|
+
JSON.unparse('error' => 'Keep out!')
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
<tt>token.owner</tt> returns the <tt>ResourceOwner</tt> that issued the token.
|
270
|
+
A token represents the fact that a single owner gave a single client a set of
|
271
|
+
permissions.
|
272
|
+
|
273
|
+
|
274
|
+
=== Transport security
|
275
|
+
|
276
|
+
Your application should ensure that any endpoint that receives or returns OAuth
|
277
|
+
data is only accessible over a secure transport such as the <tt>https:</tt>
|
278
|
+
protocol. <tt>OAuth2::Provider</tt> can enforces this to make it easier to keep
|
279
|
+
your users' data secure. If you want to enable these behaviours, set
|
280
|
+
<tt>OAuth2::Provider.enforce_ssl = true</tt>.
|
281
|
+
|
282
|
+
* The <tt>OAuth2::Provider.parse</tt> method will produce error responses and
|
283
|
+
will not process the incoming request unless the request was made using the
|
284
|
+
<tt>https:</tt> protocol.
|
285
|
+
* An access token constructed using <tt>OAuth2::Provider.access_token</tt> will
|
286
|
+
return <tt>false</tt> for <tt>#valid?</tt> unless the request was made using the
|
287
|
+
<tt>https:</tt> protocol.
|
288
|
+
* Any access token received over an insecure connection is immediately destroyed
|
289
|
+
to prevent eavesdroppers getting access to the user's resources. A client
|
290
|
+
making an insecure request will have to send the user through the authorization
|
291
|
+
process again to get a new token.
|
292
|
+
|
293
|
+
|
294
|
+
== License
|
295
|
+
|
296
|
+
Copyright (c) 2010-2011 Songkick.com
|
297
|
+
|
298
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
299
|
+
of this software and associated documentation files (the "Software"), to deal
|
300
|
+
in the Software without restriction, including without limitation the rights
|
301
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
302
|
+
copies of the Software, and to permit persons to whom the Software is
|
303
|
+
furnished to do so, subject to the following conditions:
|
304
|
+
|
305
|
+
The above copyright notice and this permission notice shall be included in
|
306
|
+
all copies or substantial portions of the Software.
|
307
|
+
|
308
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
309
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
310
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
311
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
312
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
313
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
314
|
+
THE SOFTWARE.
|
data/example/README.rdoc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
2
|
+
require dir + '/environment'
|
3
|
+
|
4
|
+
require 'sinatra'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
set :static, true
|
8
|
+
set :public, dir + '/public'
|
9
|
+
set :views, dir + '/views'
|
10
|
+
enable :sessions
|
11
|
+
|
12
|
+
PERMISSIONS = {
|
13
|
+
'read_notes' => 'Read all your notes'
|
14
|
+
}
|
15
|
+
|
16
|
+
ERROR_RESPONSE = JSON.unparse('error' => 'No soup for you!')
|
17
|
+
|
18
|
+
get('/') { erb(:home) }
|
19
|
+
|
20
|
+
|
21
|
+
get '/users/new' do
|
22
|
+
@user = User.new
|
23
|
+
erb :new_user
|
24
|
+
end
|
25
|
+
|
26
|
+
post '/users/create' do
|
27
|
+
@user = User.create(params)
|
28
|
+
if @user.save
|
29
|
+
erb :create_user
|
30
|
+
else
|
31
|
+
erb :new_user
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#================================================================
|
36
|
+
# Register applications
|
37
|
+
|
38
|
+
get '/oauth/apps/new' do
|
39
|
+
@client = OAuth2::Model::Client.new
|
40
|
+
erb :new_client
|
41
|
+
end
|
42
|
+
|
43
|
+
post '/oauth/apps' do
|
44
|
+
@client = OAuth2::Model::Client.new(params)
|
45
|
+
if @client.save
|
46
|
+
session[:client_secret] = @client.client_secret
|
47
|
+
redirect("/oauth/apps/#{@client.id}")
|
48
|
+
else
|
49
|
+
erb :new_client
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
get '/oauth/apps/:id' do
|
54
|
+
@client = OAuth2::Model::Client.find_by_id(params[:id])
|
55
|
+
@client_secret = session[:client_secret]
|
56
|
+
erb :show_client
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#================================================================
|
61
|
+
# OAuth 2.0 flow
|
62
|
+
|
63
|
+
# Initial request exmample:
|
64
|
+
# /oauth/authorize?response_type=token&client_id=7uljxxdgsksmecn5cycvug46v&redirect_uri=http%3A%2F%2Fexample.com%2Fcb&scope=read_notes
|
65
|
+
[:get, :post].each do |method|
|
66
|
+
__send__ method, '/oauth/authorize' do
|
67
|
+
@user = User.find_by_id(session[:user_id])
|
68
|
+
@oauth2 = OAuth2::Provider.parse(@user, request)
|
69
|
+
redirect @oauth2.redirect_uri if @oauth2.redirect?
|
70
|
+
|
71
|
+
headers @oauth2.response_headers
|
72
|
+
status @oauth2.response_status
|
73
|
+
|
74
|
+
@oauth2.response_body || erb(:login)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
post '/login' do
|
79
|
+
@user = User.find_by_username(params[:username])
|
80
|
+
@oauth2 = OAuth2::Provider.parse(@user, request)
|
81
|
+
session[:user_id] = @user.id
|
82
|
+
erb(@user ? :authorize : :login)
|
83
|
+
end
|
84
|
+
|
85
|
+
post '/oauth/allow' do
|
86
|
+
@user = User.find_by_id(session[:user_id])
|
87
|
+
@auth = OAuth2::Provider::Authorization.new(@user, params)
|
88
|
+
if params['allow'] == '1'
|
89
|
+
@auth.grant_access!
|
90
|
+
else
|
91
|
+
@auth.deny_access!
|
92
|
+
end
|
93
|
+
redirect @auth.redirect_uri
|
94
|
+
end
|
95
|
+
|
96
|
+
#================================================================
|
97
|
+
# Domain API
|
98
|
+
|
99
|
+
get '/me' do
|
100
|
+
authorization = OAuth2::Provider.access_token(nil, [], request)
|
101
|
+
headers authorization.response_headers
|
102
|
+
status authorization.response_status
|
103
|
+
|
104
|
+
if authorization.valid?
|
105
|
+
user = authorization.owner
|
106
|
+
JSON.unparse('username' => user.username)
|
107
|
+
else
|
108
|
+
ERROR_RESPONSE
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
get '/users/:username/notes' do
|
113
|
+
verify_access :read_notes do |user|
|
114
|
+
notes = user.notes.map do |n|
|
115
|
+
{:note_id => n.id, :url => "#{host}/users/#{user.username}/notes/#{n.id}"}
|
116
|
+
end
|
117
|
+
JSON.unparse(:notes => notes)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
get '/users/:username/notes/:note_id' do
|
122
|
+
verify_access :read_notes do |user|
|
123
|
+
note = user.notes.find_by_id(params[:note_id])
|
124
|
+
note ? note.to_json : JSON.unparse(:error => 'No such note')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
helpers do
|
131
|
+
#================================================================
|
132
|
+
# Check for OAuth access before rendering a resource
|
133
|
+
def verify_access(scope)
|
134
|
+
user = User.find_by_username(params[:username])
|
135
|
+
token = OAuth2::Provider.access_token(user, [scope.to_s], request)
|
136
|
+
|
137
|
+
headers token.response_headers
|
138
|
+
status token.response_status
|
139
|
+
|
140
|
+
return ERROR_RESPONSE unless token.valid?
|
141
|
+
|
142
|
+
yield user
|
143
|
+
end
|
144
|
+
|
145
|
+
#================================================================
|
146
|
+
# Return the full app domain
|
147
|
+
def host
|
148
|
+
request.scheme + '://' + request.host_with_port
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|