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?

You can use either header authentication or basic authentication

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.