Oauth and dynamic development url

We are developing workflows within a gitpod environment, so we have a local n8n self-hosted instance in each development workspace.

We have a problem with the n8n salesforce node credentials in that salesforce requires a “fixed” url for callbacks, and our workspaces have dynamic urls

I was looking into using an oauth proxy for the callback , but there seems to be no way to

  1. change the callback url in the credentials
  2. add a state query parameter to the initial oauth request

Has anyone else come across this type of problem and if so, were you able to solve it ?

n8n version : 1.26
running in docker
O/S is linux

It looks like your topic is missing some important information. Could you provide the following if applicable.

  • n8n version:
  • Database (default: SQLite):
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):
  • Operating system:

Hey @jmls,

I know on n8n cloud we use a shared URL for all instances so it is possible, Looking at the documentation you will need to create a hooks file that sets oauth2.callback you can find a bit more on this and what it expects in the embed documentation here: Configuration | n8n Docs

Thanks @Jon for the help. Maybe I’m doing something wrong, but I have

created a hook file and added the file to “EXTERNAL_HOOK_FILES”

module.exports = {
  frontend: {
    settings: [
      async function (settings) {
        settings.oauthCallbackUrls.oauth1 =
          'https://myfoo/callback';
        settings.oauthCallbackUrls.oauth2 =
          'https://myfoo/callback';

        console.log('FRONTEND:SETTINGS', settings);
      },
    ],
  }
};

When I start n8n, i get the message in the console

FRONTEND:SETTINGS {
[snip]
  versionCli: '1.26.0',
  releaseChannel: 'stable',
  oauthCallbackUrls: {
    oauth1: 'myfoo/callback',
    oauth2: 'myfoo/callback'
  },

So I know the hook has been called and the values changed.

If, however, I go and then create an ouath credential, the callback url is still the gitpod workspace url, not the changed setting

:person_shrugging:

Hey @jmls,

If you check you url and include /rest/settings does it show the oauth urls there?

the rest/settings url returns the callbacks as

"oauthCallbackUrls":{
   "oauth1":"https://5d0ui8celgq.ws.gitpod.io/service/automation/rest/oauth1-credential/callback",
   "oauth2":"https://5d0ui8celgq.ws.gitpod.io/service/automation/rest/oauth2-credential/callback"},

and the console.log above shows

 releaseChannel: 'stable',
  oauthCallbackUrls: {
    oauth1: "https://myfoo/callback",
    oauth2: "https://myfoo/callback"
  }

something isn’t computing :wink:

@Jon am I missing something ? Do I need to “save” the settings somehow ?

Hey @jmls,

Looking at the docs the settings example looks like it might just be cosmetic as there is also the backend hook that needs oauth2.callback as well so there is likely to be a 2 step process to this one to update the display value and one to set the value that is actually used.

We don’t really have any examples on what to do to get this working but I do know we have a version of it we use for n8n cloud so I know this can work it is just going to be finding the details on it.

@Jon

so I changed the hook to look like this

module.exports = {
  n8n: {
    ready: [
      async function (settings) {
        console.log('n8n:ready', settings);
      },
    ],
  },
  oauth2: {
    callback: [
      async function (settings) {
        console.log('oauth2:callback', settings);
      },
    ],
  },
};

in the log file I get the “n8n:ready” but do not get the “oauth2:callback” message

Does this hook only execute when a callback is requested or is it meant to be run on startup ?

Hmm, even if I get this rewriting of the callback to work I’m not sure that it will solve the problem.

I was going to use oauth2-proxy but need to pass a query parameter “rd” to set the actual workspace url to redirect back to once auth has taken place

I can’t see how I can add this parameter anywhere :frowning:

These are great questions but sadly the hooks are not something I have spent a lot of time with myself, Typically this is a feature that would only be used by an embed or enteprise customer if you are using one of these versions it may be worth reaching out to your account manager who may be able to find more information on this from other customers using it.

Failing that @marcus may have an idea.

So the oauth2:callback is actually working for me, using your hooks file. But it will be executed when the callback is coming back after you logged in. If I understand correctly you do want to change the callback url before doing an oauth login.

Sadly I also wasn’t able to use the frontend:settings hooks either to change the oauthCallbackUrls. I will ask internally if this is the right approach.

Thanks for the info @marcus and @Jon

yeah , after login is too late :wink:

We’re running in a dynamic environment, so the callback url is not known up front. So I was thinking of setting up a oauth proxy, setting the callback in the IDP to use the proxy address.

So I now need 2 things from n8n

  1. The ability to change the callback url on startup, either by a env variable or hook
  2. the ability to add a query parameter to the initial call to the IDP so that the ouath proxy knows where to redirect to (the dynamic n8n instance) after the client has been authorised

I was hoping that the hooks would solve (1) but still have the issue with (2)

What could also be useful is a “pre-auth” hook that is run just before the credential makes it’s initial call to the idp

Hey @jmls,
here is an example backend hook file to change the callback url. The frontend:settings hook trick is to prevent n8n from overriding the urls again :smiley:

const OAUTH_BASE_URL = "https://n8n.example.com"

const oauthCallbackUrls = Object.freeze({
  oauth1: OAUTH_BASE_URL + '/oauth1/callback',
  oauth2: OAUTH_BASE_URL + '/oauth2/callback',
});

module.exports = {
  frontend: {
    settings: [
      async function (settings) {
        // Prevent n8n from overwriting these urls
        Object.defineProperty(settings, 'oauthCallbackUrls', {
          get: () => oauthCallbackUrls,
          set: () => {},
        });
        console.log("frontend:settings", settings);
      },
    ],
  },
  oauth2: {
    authenticate: [
      async function (options) {
        options.redirectUri = OAUTH_BASE_URL + '/oauth2/callback';
        console.log("oauth2:authenticate", options);
      },
    ],
    callback: [
      async function (options) {
        options.redirectUri = OAUTH_BASE_URL + '/oauth2/callback';
        console.log("oauth2:callback", options);
      },
    ],
  },
};

Now we still have to figure out 2. how to add a query parameter.

1 Like