I could not find a way in documentation to use JWT authentication using cookies instead of the Bearer scheme in headers which requires you to store the JWT in localStorage (which can be a fatal in case of an XSS vulnerability). For reference: Where to store JWTs.
This would require recognising the token as:
GET /login
Host: postgrest.com
Cookie: access_token=eyJhbGciOiJIUzI1NiIsI.eyJpc3MiOiJodHRwczotcGxlL.mFrs3Zo8eaSNcxiNfvRh9dqKP4F1cB;
Seems like a perfect fit to rewrite this in the reverse proxy layer. nginx, apache etc. are all able to read and write HTTP headers while proxying a request.
But, how are Cookies less vulnerable to XSS than localstorage?
Edit: I see in your link, HttpOnly. Cookie technology must have moved on from what I knew back in the days...
Using a reverse proxy is a fair point, thanks. But it would be better if this could be integrated in the main project as it is a valid use case and easy to implement (probably).
@tocttou have you investigated doing the proxy thing? If so I'd love an nginx snippet to include in the docs.
Hello
Yes I was able to get it working using lua-nginx-module to rewrite the request.
If your Postgrest API server is on http://localhost:3000 and your Nginx Proxy is on http://localhost:3001, you can use this nginx proxy config and make request to your nginx proxy with a cookie access_token that contains the jwt (it rewrites the headers to include a Authorization: Bearer <jwt> header:
server {
listen 0.0.0.0:3001;
location / {
rewrite_by_lua_block {
local cookie_value = ngx.req.get_headers()["Cookie"]
if cookie_value ~= nil then
local jwt = cookie_value:match("access_token=([^ ]+)")
ngx.req.set_header("Authorization", "Bearer " .. jwt)
end
ngx.req.clear_header("Cookie")
}
proxy_pass http://0.0.0.0:3000;
}
}
Actual request (to nginx proxy by the client):
GET HTTP/1.1
Host: localhost:3001
Cookie: access_token=mah.osum.token
Request relayed to Postgrest:
GET HTTP/1.1
Host: localhost:3000
Authorization: Bearer mah.osum.token
Note that the regex used to extract the access_token only works correctly when there is a single cookie.
Closing this since implementation in OpenResty is the preferred way. The only way to add is there is a better way to read the cookie like this
local ck = require 'resty.cookie'
local cookie = ck:new()
local token = cookie:get('COOKIE_NAME_HERE')
What I did is setting local config in login plpgsql function, and do the transfer job in nginx (without lua).
_cookie := format('[{"set-cookie": "access_token=%s; path=/; HttpOnly; max-age=86400"}]', _token);
PERFORM set_config('response.headers', _cookie, true);
expected postgrest would support to read token from cookie, but currently seems not. So I have to transfer token from cookie header to authorizaition header.
if ($cookie_access_token) {
set $auth "Bearer $cookie_access_token";
}
if ($http_authorization) {
set $auth $http_authorization;
}
proxy_set_header Authorization $auth;
I hope it could support to read access_token or session_token in cookie header as jwt token.
expected postgrest would support to read token from cookie, but currently seems not
I would appreciate this option too
Most helpful comment
Hello
Yes I was able to get it working using lua-nginx-module to rewrite the request.
If your Postgrest API server is on
http://localhost:3000and your Nginx Proxy is onhttp://localhost:3001, you can use this nginx proxy config and make request to your nginx proxy with a cookieaccess_tokenthat contains the jwt (it rewrites the headers to include aAuthorization: Bearer <jwt>header:Actual request (to nginx proxy by the client):
Request relayed to Postgrest:
Note that the regex used to extract the
access_tokenonly works correctly when there is a single cookie.