traefiktraefik-authentication

Can traefik's forwardAuth middleware be used to secure a browser page (not an api)?


I need to secure a web page with a token stored in a cookie or url param. All examples I can find for using forwardAuth middleware seems to be for securing an API, as it's easy to supply headers in an API request. Sending custom headers isn't an option w/ the browser, so I need to used cookies.

I would like to have the auth token passed in through a query string arg, eg ?token=ABCDEFG, then stored in a cookie for future requests. Here's what the workflow looks like:

auth workflow diagram

I've tried experimenting with forwardAuth to see how I can do this. The auth endpoint reads the Authorization header, but I need something that reads the cookie in the request and transforms that to an Authorization header.

Is there any way this can be done with Traefik?


Solution

  • It looks like the answer is yes. Originally I had thought traefik wouldn't forward cookies, but it does in fact appear to forward cookies.

    I ended up creating a "sidecar" auth container on the same host as traefik so that auth requests would be faster.

    The auth function looks like this (node/express):

    app.get('/auth', (req, res) => {
      logger.info('CHECKING AUTH');
    
      const url = new URL(`${req.headers['x-forwarded-proto']}://` +
                          `${req.headers['x-forwarded-host']}` +
                          `${req.headers['x-forwarded-uri']}`);
    
      const urlAuthToken = url.searchParams.get('token');
    
      if (urlAuthToken) {
        url.searchParams.delete('token');
        const domain = BASE_DOMAIN;
        const sameSite = false;
        const secure = url.protocol === 'https:';
        return res
            .cookie('auth-token', urlAuthToken, {domain, sameSite, secure})
            .redirect(url.toString());
      }
    
      // Simulate credentials check
      if (req.cookies['auth-token'] === 'my-little-secret') {
        return res.status(200).send();
      }
    
      return res.status(401).send('<h1>401: Unauthorized</h1>');
    });