Postgrest: Use JWT through cookies instead of Bearer scheme in headers

Created on 11 Dec 2016  路  7Comments  路  Source: PostgREST/postgrest

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;

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: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.

All 7 comments

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

Was this page helpful?
0 / 5 - 0 ratings