Self hosted user management

Hi, when hosting n8n self, is it possible to put it behind a reverse proxy and so bypass the user management of n8n? I’d like to have the authentication on the proxy since multiple applications run behind the proxy.
Thank you

Hi @pfiadDi, this should be possible in theory.

I am still running [email protected] on my private instance which is the last version supporting basic auth. I then have my Identity Provider (Authentik) attach basic auth credentials to the relevant requests, and most reverse proxies will also be able to inject the required headers.

For n8n version v1 you’d need to hack a bit. I have not set this up myself yet, but a while back @netroy shared a hooks file with me that should handle the log in using basic auth credentials:

const { dirname, resolve } = require('path')
const Layer = require('express/lib/router/layer')
const basicAuth = require('basic-auth')
const { issueCookie } = require(resolve(dirname(require.resolve('n8n')), 'auth/jwt'))

const basicAuthCredentials = {
  username: process.env.N8N_BASIC_AUTH_USER,
  password: process.env.N8N_BASIC_AUTH_PASSWORD,
}

const ignoreAuthRegexp = /^\/(assets|healthz|webhook)/;

module.exports = {
  n8n: {
    ready: [
      async function ({ app }, config) {
        await this.dbCollections.Settings.update(
          { key: 'userManagement.isInstanceOwnerSetUp' },
          { value: JSON.stringify(true) },
        )

        config.set('userManagement.isInstanceOwnerSetUp', true)

        const { stack } = app._router;

        if (basicAuthCredentials.username && basicAuthCredentials.password) {
          stack.unshift(new Layer('/', {
            strict: false,
            end: false
          }, async (req, res, next) => {
            if (ignoreAuthRegexp.test(req.url)) return next();
  
            const authorization = basicAuth(req);
            if (!authorization || authorization.name !== basicAuthCredentials.username || authorization.pass !== basicAuthCredentials.password) {
              res.statusCode = 401
              res.setHeader('WWW-Authenticate', 'Basic realm="n8n"')
              res.end('Access denied')
            } else {
              next()
            }
          }))
        }

        const index = stack.findIndex((l) => l.name === 'cookieParser')
        stack.splice(index + 1, 0, new Layer('/', {
          strict: false,
          end: false
        }, async (req, res, next) => {
          if (!req.cookies?.['n8n-auth']) {
            const owner = await this.dbCollections.User.findOneBy({
              globalRole: {
                name: 'owner',
                scope: 'global',
              },
            })
            issueCookie(res, owner)
          }

          next()
        }))

        console.log("UM Disabled")
      },
    ],
  },
}

Perhaps you want to give this a go and let us know how it goes? The n8n.ready hook would be a backend hook.

1 Like

Thank you - I’ll try that. If not this, than next week

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.