Webhook Authentication

On the “Webhook Creating Endpoints Part 2” video on YouTube, a proper way to authenticate users is mentioned but not described. What is the proper way to secure Webhooks on n8n?

1 Like

You can use either header authentication or basic authentication

1 Like

Ricardo,

there are other Auth Methods in Pipeline ? OAuth ? Or do we need to implement this via Proxy ?

Thanks,
Stefan

We have many more authentication method in the HTTP node. What do you want to do exactly?

Been trying to Basic authenticate a POST webhook in test-mode from self-hosted Seatable.
Wasn’t able to find an example on either the documentation or the forum, though I’m probably not the first doing this.

I thought this would be enough:

const username = "n8n-basic-auth-USER";
const password = "n8n-basic-auth-PASSWORD";
let data = {
  row_id: base.context.currentRow['_id']
};

await fetch(url, {
  method: 'POST',
  credentials: 'include',
  mode: "no-cors",
  headers: {
    'Content-Type': 'application/json', 
    'Authorization': "Basic " + btoa(`${username}:${password}`)
  },
  body: JSON.stringify(data)
}).then(res => {
  console.log('Request complete! response:', res);
});

I get a 403 Error and been looking at specifications for a while now, trying different things.
It’s probably an easy fix, one suspicion I have is that the request from Seatable Javascript script originates from seatable.mydomain.com and goes to n8n.mydomain.com and gets rejected?

In n8n I have set my Basic Auth credentials with User = ‘n8n-basic-auth-USER’ and Password = ‘n8n-basic-auth-PASSWORD’ (in reality a 44-character string with uppercase, lowercase, digits).

Without authentication it works fine, so I guess I’m fucking up somewhere essential and can’t see it right now : D Any pointers would be much appreciated!

Information on your n8n setup

  • n8n version: 0.193.5
  • Database you’re using (default: SQLite): Postgres
  • Running n8n with the execution process [own(default), main]: main
  • Running n8n via [Docker, npm, n8n.cloud, desktop app]: Docker
    Using traefik as a reverse proxy.
    Not using user management, but Basic Auth for logging into my n8n.

Hi Ricardo, That a Webhook Endpoint in N8n can use Auth Method OAuth2. What do you think ?
Regards,
Stefan

Hey folks — jumping in with two parts: a quick clarification on OAuth2/JWT for webhooks and a ready-made option if you need stronger security patterns in n8n.

1) “OAuth on a webhook?”

Webhooks typically don’t perform an OAuth2 handshake themselves. Instead, the sender (client) obtains an OAuth2 access token and calls your webhook with
Authorization: Bearer <token>.
On the webhook side you verify the token — ideally using JWKS from your IdP (Auth0/Okta/OIDC). That’s the standard “JWT (JWKS)” verification approach.

2) Basic Auth + browser request (Seatable) → 403

If you’re calling your webhook from code that runs in the browser on seatable.mydomain.com to n8n.mydomain.com, you’ll hit CORS:

  • Remove mode: "no-cors" (that makes the request opaque and hides errors).

  • Make sure your proxy/n8n answers preflight with the right headers, e.g.:

    • Access-Control-Allow-Origin: https://seatable.mydomain.com

    • Access-Control-Allow-Headers: content-type, authorization

    • Access-Control-Allow-Methods: POST, OPTIONS

  • Sanity-check from a server (no CORS) to confirm credentials are fine:

    curl -i -X POST 'https://n8n.mydomain.com/webhook/<path>' \
      -H 'content-type: application/json' \
      -u 'n8n-basic-auth-USER:n8n-basic-auth-PASSWORD' \
      --data '{"ok":true}'
    
    

If curl works but the browser doesn’t, it’s a pure CORS/proxy config issue (not auth).

A hardened webhook trigger for n8n (open source)

We built a community node that adds defense-in-depth for public endpoints:

  • Auth profiles: HMAC (with timestamp+nonce), JWT (JWKS), API Key, or Combo (HMAC + IP allow/deny)

  • Replay protection (timestamp + nonce)

  • Rate limiting per IP (memory or Redis)

  • Content-Type allowlist & body size caps

  • mTLS proof via proxy headers (e.g., x-ssl-client-verify: SUCCESS)

  • Audit export (metadata-only) and dual-key rotation for HMAC

Install (Community Nodes): @prokodo/n8n-nodes-secure-webhook
Then pick one of the variants: Secure Webhook (HMAC), (JWT/JWKS), (API Key), or (Combo).

JWT/JWKS (for OAuth2 access tokens)

  • Set your IdP JWKS URL, and (optionally) iss/aud.

  • Clients call with Authorization: Bearer <jwt> — the node verifies via JWKS.

HMAC (extended mode) client example

import crypto from 'node:crypto';
const url = 'https://n8n.example/webhook/secure';
const body = JSON.stringify({ hello: 'world' });
const ts = Math.floor(Date.now()/1000).toString();
const nonce = crypto.randomUUID();
const algo = 'sha256';
const bodyHash = crypto.createHash(algo).update(Buffer.from(body)).digest('hex');
const base = ['POST', '/webhook/secure', '', ts, nonce, bodyHash].join('\n');
const sig = crypto.createHmac(algo, process.env.WEBHOOK_SECRET).update(base).digest('hex');

await fetch(url, {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'x-timestamp': ts,
    'x-nonce': nonce,
    'x-signature': `${algo}=${sig}`,
  },
  body,
});

Happy to share a minimal Traefik/Nginx CORS snippet if helpful. If you need JWT verification for OAuth2 or stronger webhook hardening, this node should cover it.