Tweaks the text, adds a design remark about SQL functions and adds the token TTL in HTTP cache headers

This commit is contained in:
Diogo Biazus
2015-12-20 14:45:22 -05:00
parent 1d848b8d72
commit eef4e3c647
+29 -13
View File
@@ -21,7 +21,7 @@ so I'm assuming that the reader's authentication system is already working.
### Sharing the JWT Secret ### Sharing the JWT Secret
To allow a third party to generate valid JWTs for your PostgREST API Allowing a third party to generate valid JWTs for your PostgREST API
is just a matter of sharing a secret. So you need to give your authenticator is just a matter of sharing a secret. So you need to give your authenticator
software the same secret that was used in your API server under the ```--jwt-secret``` software the same secret that was used in your API server under the ```--jwt-secret```
parameter. parameter.
@@ -42,11 +42,11 @@ I'll add a text field called role to my users table:
ALTER TABLE users ADD role text NOT NULL DEFAULT 'customer'; ALTER TABLE users ADD role text NOT NULL DEFAULT 'customer';
``` ```
For our example we will need besides the main user that PostgREST uses to connect to PostgreSQL Besides the main user that PostgREST uses to connect to PostgreSQL
and the anonymous user, we will have two aditional roles: and the anonymous user, we will need two aditional roles for our example:
* admin - to be used by users where admin = true * admin - to be used by users that access all the system rows.
* customer - to be used where admin = false * customer - to be used when user has restricted access to database rows.
Bellow we have the commands to create all roles that will be used: Bellow we have the commands to create all roles that will be used:
```sql ```sql
@@ -55,7 +55,7 @@ CREATE ROLE anonymous;
CREATE ROLE admin; CREATE ROLE admin;
CREATE ROLE customer; CREATE ROLE customer;
GRANT customer, admin, anonymous TO postgrest; GRANT customer, admin, anonymous TO authenticator;
``` ```
### Generating a JWT ### Generating a JWT
@@ -75,6 +75,8 @@ For this I just open a file ```app/controllers/api_tokens_controller.rb``` with
```ruby ```ruby
class ApiTokensController < ApplicationController class ApiTokensController < ApplicationController
TOKEN_TTL = 1.hour
def show def show
unless ENV['JWT_SECRET'].present? unless ENV['JWT_SECRET'].present?
return render json: {error: "you need to have JWT_SECRET configured to get an API token"}, status: 500 return render json: {error: "you need to have JWT_SECRET configured to get an API token"}, status: 500
@@ -84,6 +86,7 @@ class ApiTokensController < ApplicationController
return render json: {error: "only authenticated users can request the API token"}, status: 401 return render json: {error: "only authenticated users can request the API token"}, status: 401
end end
expires_in TOKEN_TTL, public: false
render json: {token: jwt}, status: 200 render json: {token: jwt}, status: 200
end end
@@ -93,10 +96,12 @@ class ApiTokensController < ApplicationController
end end
def claims def claims
# I'm assuming a boolean field admin in the user model indicating wheter the
# user has administrative privileges.
# This token will expire 1 hour after being issued # This token will expire 1 hour after being issued
{ role: current_user.role, user_id: current_user.id.to_s, exp: (Time.now + 1.hour).to_i } {
role: current_user.role,
user_id: current_user.id.to_s,
exp: (Time.now + TOKEN_TTL).to_i
}
end end
end end
``` ```
@@ -113,8 +118,9 @@ whose value is the token the API requests should use.
### Orders Endpoint ### Orders Endpoint
Here we describe how to create a view to generate an endpoint /orders filtered by Here is how to create a view to generate an endpoint ```/orders``` filtered by
the logged in user. the logged in user:
```sql ```sql
ALTER DATABASE mydb SET postgrest.claims.user_id TO ''; ALTER DATABASE mydb SET postgrest.claims.user_id TO '';
@@ -144,10 +150,20 @@ WHERE
current_user = 'admin' OR o.user_id = current_user_id(); current_user = 'admin' OR o.user_id = current_user_id();
``` ```
<div class="admonition note">
<p class="admonition-title">DRY priviledge checking conditions</p>
<p>
You can encapsulate conditions that will be commonly used to check for privileges while reading a database row.
We used a function <code>current_user_id()</code> but we could add more conditions to functions
as the system becomes more complex.<br/>
Remeber to mark your functions as <code>STABLE</code> so that PostgreSQL can inline then while planning the query.
</p>
</div>
### Using the JWT ### Using the JWT
Now any page generated by our Rails app, after we are authenticated we can use a simple Now whenever you are authenticated in your Rails application you can use some Javascript
Javascript code to get our token and use it: code to get the token and use it:
```javascript ```javascript
$.getJSON('/api_json').done(function(data){ $.getJSON('/api_json').done(function(data){
$.ajax('/orders', {'Authorization': 'Bearer ' + data.token}) $.ajax('/orders', {'Authorization': 'Bearer ' + data.token})