Skip to content

Commit cf6f847

Browse files
simplify api, we don't like users who don't use js
1 parent a978511 commit cf6f847

File tree

12 files changed

+43
-129
lines changed

12 files changed

+43
-129
lines changed

db/src/api/login.sql

+24-58
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
-- we have multiple scenarious.
2-
-- base case everything is allowed
3-
-- no cookie allowed in frontend
4-
-- no js allowed in frontend
5-
--
6-
71
-- BASE CASE
82
-- Token should be saved to sessionStorage
93
-- Refresh-token should be saved in cookie which only server can setup.
104

11-
create or replace function login(email text, password text, jwt_cookie boolean DEFAULT false, rt_cookie boolean DEFAULT false, csrf boolean DEFAULT true, csrf_token text DEFAULT null ) returns json as $$
5+
create or replace function login(email text, password text, cookie boolean DEFAULT false, csrf text DEFAULT null ) returns json as $$
126
declare
137
usr record;
148
ses record;
@@ -23,68 +17,40 @@ begin
2317
raise invalid_password using detail = 'Invalid email or password', hint = 'Make sure your email and password are correct!';
2418
else
2519
head := request.header('host') || '-' || request.header('user-agent');
26-
if jwt_cookie is true then
27-
token := pgjwt.sign(
28-
json_build_object(
29-
'role', usr.role,
30-
'user_id', usr.id,
31-
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int,
32-
'user-agent', head
33-
),
34-
settings.get('jwt_secret')
35-
);
36-
else
37-
token := pgjwt.sign(
38-
json_build_object(
39-
'role', usr.role,
40-
'user_id', usr.id,
41-
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int
42-
),
43-
settings.get('jwt_secret')
44-
);
45-
end if;
46-
47-
if csrf_token is not null then
48-
delete from data."session" where csrf=csrf_token; -- remove old refresh token for this user with device
20+
token := pgjwt.sign(
21+
json_build_object(
22+
'role', usr.role,
23+
'user_id', usr.id,
24+
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int
25+
),
26+
settings.get('jwt_secret')
27+
);
28+
29+
if csrf is not null then
30+
delete from data."session" where csrf=csrf; -- remove old refresh token for this user with device
4931
end if;
5032

5133
-- TODO add more info, like IP address, Location to logs, and to session.
5234
insert into data."session" as s
53-
(user_id, device_name, csrf, exp) values (usr.id, head, util.ifnull(csrf, pgjwt.url_encode(convert_to(replace(uuid_generate_v4()::text, '-', ''), 'utf8'))), extract(epoch from now())::integer + settings.get('refresh_token_lifetime')::int)
35+
(user_id, device_name, csrf, exp) values (usr.id, head, pgjwt.url_encode(convert_to(replace(uuid_generate_v4()::text, '-', ''), 'utf8')), extract(epoch from now())::integer + settings.get('refresh_token_lifetime')::int)
5436
returning *
5537
into ses;
5638

57-
if jwt_cookie is true then
58-
perform response.set_cookie('JWTTOKEN', token, settings.get('jwt_lifetime')::int,'/');
59-
end if;
60-
61-
if rt_cookie is true then
39+
if cookie is true then
6240
perform response.set_cookie('REFRESHTOKEN', ses.id::text, settings.get('refresh_token_lifetime')::int,'/'::text);
6341
end if;
6442

65-
if csrf is true then
66-
return json_build_object(
67-
'id', usr.id,
68-
'name', usr.name,
69-
'email', usr.email,
70-
'role', usr.role::text,
71-
'token', token::text,
72-
'refresh_token', ses.id::text,
73-
'csrf', ses.csrf::text
74-
);
75-
else
76-
return json_build_object(
77-
'id', usr.id,
78-
'name', usr.name,
79-
'email', usr.email,
80-
'role', usr.role::text,
81-
'token', token::text,
82-
'refresh_token', ses.id::text
83-
);
84-
end if;
85-
43+
return json_build_object(
44+
'id', usr.id,
45+
'name', usr.name,
46+
'email', usr.email,
47+
'role', usr.role::text,
48+
'token', token::text,
49+
'refresh_token', ses.id::text,
50+
'csrf', ses.csrf::text
51+
);
8652
end if;
8753
end
8854
$$ volatile security definer language plpgsql;
8955
-- by default all functions are accessible to the public, we need to remove that and define our specific access rules
90-
revoke all privileges on function login(text, text, boolean, boolean, boolean, text) from public;
56+
revoke all privileges on function login(text, text, boolean, text) from public;

db/src/api/logout.sql

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ begin
44
if refresh_token is not null then
55
delete from data."session" where id=refresh_token::uuid;
66
end if;
7-
perform response.delete_cookie('JWTTOKEN');
87
perform response.delete_cookie('REFRESHTOKEN');
98
return json_build_object('ok', true);
109

db/src/api/refresh_token.sql

+10-23
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
create or replace function refresh_token(refresh_token text, csrf text default null, jwt_cookie boolean default false ) returns json as $$
1+
create or replace function refresh_token(refresh_token text, csrf text default null ) returns json as $$
22
declare
33
usr record;
44
ses record;
@@ -28,30 +28,17 @@ begin
2828
where id = ses.id;
2929

3030

31-
if jwt_cookie is true then
32-
head := request.header('host') || '-' || request.header('user-agent');
33-
token := pgjwt.sign(
34-
json_build_object(
35-
'role', usr.role,
36-
'user_id', usr.id,
37-
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int,
38-
'user-agent', head
39-
),
40-
settings.get('jwt_secret')
41-
);
42-
else
43-
token := pgjwt.sign(
44-
json_build_object(
45-
'role', usr.role,
46-
'user_id', usr.id,
47-
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int
48-
),
49-
settings.get('jwt_secret')
50-
);
51-
end if;
31+
token := pgjwt.sign(
32+
json_build_object(
33+
'role', usr.role,
34+
'user_id', usr.id,
35+
'exp', extract(epoch from now())::integer + settings.get('jwt_lifetime')::int
36+
),
37+
settings.get('jwt_secret')
38+
);
5239
return json_build_object('token', token);
5340
end if;
5441
end
5542
$$ volatile security definer language plpgsql;
5643
-- by default all functions are accessible to the public, we need to remove that and define our specific access rules
57-
revoke all privileges on function refresh_token(text, text, boolean) from public;
44+
revoke all privileges on function refresh_token(text, text) from public;

db/src/api/register.sql

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
create or replace function register(name text, email text, password text,jwt_cookie boolean DEFAULT false, rt_cookie boolean DEFAULT false, csrf boolean DEFAULT true) returns json as $$
1+
create or replace function register(name text, email text, password text,cookie boolean DEFAULT false) returns json as $$
22
declare
33
usr record;
44
begin
@@ -7,8 +7,8 @@ begin
77
returning *
88
into usr;
99

10-
return login(usr.email, password, jwt_cookie, rt_cookie, csrf);
10+
return login(usr.email, password, cookie);
1111
end
1212
$$ security definer language plpgsql;
1313

14-
revoke all privileges on function register(text, text, text, boolean, boolean, boolean) from public;
14+
revoke all privileges on function register(text, text, text, boolean) from public;

db/src/authorization/firewall.sql

-21
This file was deleted.

db/src/authorization/privileges.sql

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
grant usage on schema api to anonymous, webuser;
99

1010
-- set privileges to all the auth flow functions
11-
grant execute on function api.login(text,text,boolean,boolean,boolean,text) to anonymous;
12-
grant execute on function api.login(text,text,boolean,boolean,boolean,text) to webuser;
13-
grant execute on function api.register(text,text,text,boolean,boolean,boolean) to anonymous;
11+
grant execute on function api.login(text,text,boolean,text) to anonymous;
12+
grant execute on function api.login(text,text,boolean,text) to webuser;
13+
grant execute on function api.register(text,text,text,boolean) to anonymous;
1414
grant execute on function api.logout(text) to webuser;
1515
grant execute on function api.me() to webuser;
16-
grant execute on function api.refresh_token(text,text,boolean) to anonymous;
17-
grant execute on function api.refresh_token(text,text,boolean) to webuser;
16+
grant execute on function api.refresh_token(text,text) to anonymous;
17+
grant execute on function api.refresh_token(text,text) to webuser;
1818

1919
-- define the who can access todo model data
2020
-- enable RLS on the table holding the data

db/src/init.sql

-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ select settings.set('refresh_token_lifetime', '2592000'); -- 30 days
5656
\echo # Loading roles and privilege settings
5757
\ir authorization/roles.sql
5858
\ir authorization/privileges.sql
59-
\ir authorization/firewall.sql
6059

6160
\echo # Loading sample data
6261
\ir sample_data/data.sql

lib/shortcodes/test.js

-5
This file was deleted.

openresty/nginx/rest.conf

-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ location /api/rpc/refresh_token {
1414
location /api {
1515
include cors.conf;
1616

17-
if ($cookie_JWTTOKEN != ""){
18-
more_set_input_headers 'Authorization: Bearer $cookie_JWTTOKEN';
19-
}
20-
2117
# rewrite for the main internal location
2218
rewrite ^/api/(.*)$ /internal/api/$1;
2319
}

rest.conf

-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ db-schema="api"
33
db-anon-role="anonymous"
44
db-pool=10
55
jwt-secret="reallyreallyreallyreallyverysafe"
6-
pre-request = "firewall"

scripts/reset-db-now.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
const reset = require('../util/reset-db')
1+
const reset = require('../util/reset-db.js')
22
reset()

todo.org

-6
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,17 @@ JWT
8181
if js
8282
- use session storage, check tab count for not reseting refresh_token \\ maybe in memory is better, because sessionStorage can be accessed ??
8383
- each tab has its own jwt token, no problem
84-
if not js
85-
if no js is allowed use cookie and check headers and origin / device, it would be nice to add it to JWT and check it with lua for security.
8684

8785
REFRESH TOKEN
8886
if js
8987
use cookie but make sure it can be written by server only,
9088
send CSRF token which will be stored in localstorage
9189
if not cookie
9290
use sessionstorage
93-
if not js
94-
cookie
95-
CSRF is not possible to send with static site :(, simply check for device headers, origins etc. maybe even IP
9691

9792

9893

9994

10095
* TODO
10196
** Front-end -> login flow for web.
102-
** Front-end -> login flow for web without js.
10397
** Create script/file to generate tailwind cheatsheet in plain text so it is easily searchable as cheatsheet.

0 commit comments

Comments
 (0)