
Complete fix guide for every n8n API key not recognized and 401 Unauthorized error
You generated the key, copied it carefully, pasted it into the header and n8n still throws 401. Most developers spend 40 minutes re-checking the key itself. The key is almost never the problem. The problem is where the key gets lost between your client and n8n’s auth middleware a trailing space, a proxy that strips custom headers, a container that never reloaded the .env, or an endpoint that simply doesn’t accept API key auth. This guide covers every scenario, with real error logs and the exact fix for each one.
Who this is for: Developers and DevOps engineers who integrate with a self‑hosted or n8n Cloud instance via its REST API. We cover this in detail in the n8n Authentication Errors Guide. If you receive “API key not recognized” from n8n, the request is missing a valid x-n8n-api-key header or the key stored in the environment variable is wrong.
Start Here: Debug Decision Tree
Most devs get stuck because they assume all 401 errors are the same. They’re not. Find your exact branch below — each path leads to the right section so you don’t waste time chasing the wrong fix.
→ YES → Q2 ↓
→ NO (OpenAI, ElevenLabs, etc. failing INSIDE n8n) → Jump to Section A
Q2. Does the exact same curl command work when hitting port 5678 directly?
→ YES (works direct, fails via domain/proxy) → Jump to Section 5 — Reverse Proxy
→ NO (fails even direct) → Q3 ↓
Q3. Did you restart n8n after setting the API key in .env?
→ NO → Restart the container, retry. Done.
→ YES → Q4 ↓
Q4. Are you calling /rest/workflows or /api/v1/workflows?
→ /rest/ with x-n8n-api-key → Jump to Section B — Wrong Endpoint
→ /api/v1/ with x-n8n-api-key → correct, go to Q5 ↓
Q5. Does the credential test show green in the UI but workflows still fail?
→ YES → Jump to Section C — Credential Test Passes but Execution Fails
→ NO → Q6 ↓
Q6. Did this start happening after a Docker restart, n8n update, or migration?
→ YES → Jump to Section D — Encryption Key Mismatch
→ NO → Work through Sections 1–4 in order (header, whitespace, key value)
Quick fix
- Verify the exact API key in Settings → API → API Key (or the
.envfile). - Ensure the request header is spelled
x-n8n-api-key(case‑insensitive) and contains no extra spaces or line‑breaks. - Restart n8n after any change to the
.envfile.
After these three steps the error should disappear.
1. Why n8n Returns “API key not recognized”
If you encounter any invalid credentials error resolve them before continuing with the setup.
| Root Cause | How n8n Detects It |
|---|---|
| Missing header | req.headers['x-n8n-api-key'] is undefined |
| Wrong header name | Header key does not match x-n8n-api-key (e.g., api-key) |
| Incorrect key value | Header value ≠ process.env.N8N_API_KEY |
| Trailing/leading whitespace | No String.trim() before comparison |
| Key not loaded | .env not re‑loaded after edit |
| Multiple API keys (Enterprise) | Request uses a key not assigned to the calling user |
Typical symptom for all cases: 401 Unauthorized with message “API key not recognized”.
Understanding the exact cause lets you target the right fix without chasing dead‑ends.
2. Locate the Correct API Key in n8n
If you encounter any token expired error resolve them before continuing with the setup.
Self‑hosted (Docker / Binary)
# Show the key stored in the .env file (default location) cat /home/n8n/.n8n/.env | grep N8N_API_KEY
If the variable is missing, generate a new one:
# Generate a 32‑byte hex string openssl rand -hex 32 # Append it to the .env file echo "N8N_API_KEY=9f2c3d4e5b6a7c8d9e0f1a2b3c4d5e6f" >> /home/n8n/.n8n/.env
n8n Cloud
- Open Settings → API → API Key in the UI.
- Click Copy; the key lives in the cloud’s secret manager (you can only regenerate, not view again).
EEFA note: Never commit the API key to source control. Use secret‑management tools (Docker secrets, Kubernetes
Secret, or.envfiles excluded via.gitignore).
3. Correctly Send the API Key in Your Request
3.1 cURL Example
curl -X GET "https://your-n8n-instance.com/rest/workflows" \
-H "x-n8n-api-key: 9f2c3d4e5b6a7c8d9e0f1a2b3c4d5e6f" \
-H "Accept: application/json"
Common pitfalls – see the table below.
| Pitfall | Symptom | Fix |
|---|---|---|
| Double quotes around the key with trailing space | 401 error | Trim spaces: x-n8n-api-key:$(echo -n "$KEY" | tr -d ' ') |
Using Authorization: Bearer <key> |
401 error | Switch to x-n8n-api-key. |
Sending key in query string (?api_key=) |
401 error | n8n only reads the header; move it to header. |
3.2 JavaScript (Node.js) Example
require('dotenv').config(); // Load .env
const fetch = require('node-fetch');
const API_URL = 'https://your-n8n-instance.com/rest/workflows';
const API_KEY = process.env.N8N_API_KEY.trim(); // Trim whitespace
Next, perform the request and handle errors:
(async () => {
const res = await fetch(API_URL, {
method: 'GET',
headers: {
'x-n8n-api-key': API_KEY,
'Accept': 'application/json',
},
});
if (!res.ok) {
const err = await res.text();
throw new Error(`Request failed (${res.status}): ${err}`);
}
const data = await res.json();
console.log(data);
})();
EEFA tip: In production, wrap the request in a retry block and log the raw request/response without the API key (mask it) to avoid leaking credentials.
4. Step‑by‑Step Troubleshooting Checklist
| Step | Action | Verification |
|---|---|---|
| 1 | Confirm the key value – open .env or UI and copy it verbatim. |
echo $N8N_API_KEY matches the UI copy. |
| 2 | Check header spelling – must be exactly x-n8n-api-key. |
curl -v shows > x-n8n-api-key: line. |
| 3 | Trim whitespace – add .trim() in code or use sed 's/ *$//'. |
No trailing spaces in logs (| delimiters). |
| 4 | Reload environment – restart Docker container or pm2 restart n8n. |
docker logs n8n | grep API_KEY shows new value. |
| 5 | Test with cURL – bypass your app to isolate the issue. | Successful JSON response. |
| 6 | Inspect n8n logs – look for API key not recognized lines. |
Log timestamp matches request. |
| 7 | Validate against multiple keys (Enterprise) – ensure the key belongs to the user. | Use the UI to view assigned keys. |
| 8 | Check reverse proxy – ensure it forwards the x-n8n-api-key header (some proxies strip unknown headers). |
Add proxy_set_header x-n8n-api-key $http_x_n8n_api_key; in Nginx config. |
If any step fails, correct the issue before moving to the next.
5. Reverse Proxy Gotchas
Many production deployments sit behind NGINX or Traefik. By default, these proxies may drop custom headers.
NGINX Example
location / {
proxy_pass http://localhost:5678;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Preserve the API key header
proxy_set_header x-n8n-api-key $http_x_n8n_api_key;
}
Traefik (Docker) Example
labels: - "traefik.http.middlewares.n8n-headers.headers.customrequestheaders.x-n8n-api-key=YOUR_KEY" - "traefik.http.routers.n8n.middlewares=n8n-headers"
EEFA warning: Hard‑coding the key in proxy config defeats the purpose of secret rotation. Prefer forwarding the original header instead of injecting a static value.
6. Regenerating a Lost or Compromised API Key
- Self‑hosted – edit
.envand replaceN8N_API_KEYwith a newly generated value (see Section 2). - n8n Cloud – go to Settings → API → Regenerate; all existing clients must be updated instantly.
Production tip: Deploy a rolling key rotation script that updates the key, notifies dependent services via a webhook, and restarts containers one at a time to avoid downtime.
7. When “API key not recognized” Persists After Fixes
| Symptom | Likely Hidden Cause | Remedy |
|---|---|---|
| 401 error despite correct header | Proxy stripping header (see Section 5) | Verify curl -v through the proxy; add proxy_set_header. |
| 401 error only for certain IPs | IP‑based firewall blocking header | Whitelist the client IP or disable the rule. |
| 401 error after Docker compose up | .env file not mounted (volume missing) |
Add volumes: - ./n8n/.env:/home/node/.n8n/.env. |
| 401 error in CI pipeline | CI secret variable not exported | Echo the variable in the CI step to confirm; use export N8N_API_KEY=.... |
Section A: External API Keys Failing Inside n8n Workflows (OpenAI, ElevenLabs, fal.ai, Pinecone)
This is the most common real-world version of this error in 2025 — and it’s completely different from n8n’s own API key. You’re not calling n8n; you’re calling an external service from inside an n8n workflow, and that service returns 401. Here’s what the error looks like in the n8n execution log:
{
"errorMessage": "Authorization failed - please check your credentials",
"errorDescription": "Request failed with status code 401",
"errorDetails": {
"rawErrorMessage": ["401 - \"{\\\"message\\\":\\\"Invalid API key\\\",\\\"statusCode\\\":401}\""],
"httpCode": "401"
},
"n8nDetails": {
"nodeName": "HTTP Request",
"nodeType": "n8n-nodes-base.httpRequest",
"n8nVersion": "1.108.1 (Self Hosted)"
}
}
If this is your error, the x-n8n-api-key header is irrelevant. The problem is how n8n is sending the external service’s credentials. Work through these fixes in order:
A1. API key works in Postman/curl but fails inside n8n
This is the single most-reported pattern across the n8n community. The key is valid — n8n is sending it wrong. Three causes in order of likelihood:
Hidden characters from copy-paste. When you paste an API key into n8n’s credential field from a browser, an email, or a PDF, invisible Unicode characters (zero-width spaces, non-breaking spaces) tag along. The credential test endpoint is sometimes more lenient than the actual API call — so it passes the test but fails on execution.
Fix: delete the key from the credential field entirely, then type the key manually or paste it into a plain text editor first to strip invisible characters, then copy from there into n8n.
Wrong authentication method selected. In the HTTP Request node, the “Authentication” dropdown matters. If the API expects Authorization: Bearer sk-xxx but you’ve selected “Header Auth” with key name Authorization and value sk-xxx (without the word “Bearer”), it fails. The correct value would be Bearer sk-xxx.
Using a dedicated node vs. HTTP Request node. n8n’s dedicated OpenAI node, ElevenLabs node, etc. use their own authentication logic separate from the HTTP Request node. If one fails, try the other to isolate whether it’s a credential problem or a node implementation problem.
A2. OpenAI sk-proj-… project-scoped keys not recognized
OpenAI introduced project-scoped API keys (format: sk-proj-...) which require an additional OpenAI-Project header. n8n’s built-in OpenAI node does not fully support this format as of mid-2025. The result:
Authorization failed - please check your credentials Missing bearer or basic authentication in header
Fix option 1 (recommended): Use a classic user API key (sk-...) instead of a project key. In the OpenAI dashboard, go to API keys → create a new key without selecting a project.
Fix option 2: Use the HTTP Request node instead of the dedicated OpenAI node and pass both required headers manually:
Authorization: Bearer sk-proj-YOUR_KEY OpenAI-Project: proj_YOUR_PROJECT_ID Content-Type: application/json
A3. Credential test shows green but execution returns 401
This is the most confusing pattern — the credential test passes, your curl works, but the actual workflow execution returns 401. Reported across ElevenLabs, OpenRouter, fal.ai, and OpenAI nodes.
Why it happens: n8n’s credential test endpoint hits a simple “ping” endpoint of the external API (often just a GET to check if the key exists). The actual operation (e.g., text-to-speech, image generation) hits a different endpoint that may have scope restrictions, usage tier limits, or require a different auth header format.
Fix sequence:
- Delete the existing credential in n8n completely.
- Create a brand new credential from scratch — do not copy-paste from the old one.
- Test by running the specific operation that was failing (not just the credential test).
- If it still fails, test the exact same API call via curl with the same key to confirm the key has access to that specific operation/endpoint.
- Check the external service’s dashboard — some APIs (ElevenLabs free tier, fal.ai) disable specific operations based on plan tier, which returns 401 even with a valid key.
# Test ElevenLabs text-to-speech directly
curl -X POST https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM \
-H "xi-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "test", "model_id": "eleven_monolingual_v1"}'
# If this returns 401, the issue is with your key/plan, not n8n
Section B: Wrong Endpoint – /rest/ vs /api/v1/ Confusion
This catches a huge number of developers. n8n has two distinct API route structures and they behave differently with API key authentication:
| Endpoint prefix | Purpose | Auth method | API key works? |
|---|---|---|---|
/api/v1/ |
Public REST API (workflows, executions, credentials) | x-n8n-api-key header |
✅ Yes |
/rest/ |
Internal editor API (used by the n8n UI itself) | Session cookie / browser auth | ❌ No – returns 401 |
The /rest/ endpoints are what n8n’s own browser UI uses. They require session-based authentication, not API key headers. If you’re hitting /rest/workflows with your API key, you’ll always get 401 regardless of how correct your key is.
Fix – use the correct public API path:
# WRONG — internal endpoint, API key doesn't work here curl -H "x-n8n-api-key: YOUR_KEY" http://localhost:5678/rest/workflows # CORRECT — public API endpoint curl -H "x-n8n-api-key: YOUR_KEY" http://localhost:5678/api/v1/workflows
For self-referencing n8n API credentials (when n8n calls its own API inside a workflow): the Base URL must be your n8n instance’s external URL, not localhost – because n8n inside Docker doesn’t reach itself via localhost. Use the container name or external domain:
# If n8n is in Docker, use the container name or service name from docker-compose Base URL: http://n8n:5678/api/v1 # NOT: http://localhost:5678/api/v1 ← this resolves inside the container, not to n8n
Section C: JWT Timestamp Bug – Fresh API Key Returns 401 Immediately
This one is genuinely surprising. You generate a brand new API key from the n8n UI, use it immediately — and get 401. You’ve verified the header, the endpoint, everything. The key is completely fresh. It still fails.
n8n API keys are JWT tokens. A confirmed bug (reported October 2025, GitHub issue #21054) causes the JWT’s iat (issued-at) timestamp to be set to a future timestamp — typically 6–7 minutes ahead of the actual current time. JWT validation rejects tokens whose iat is in the future, because it means “this token hasn’t been issued yet.” The result is a 401 that has nothing to do with your key value.
# Decode your API key (it starts with eyJ...) to check the iat field echo "YOUR_JWT_API_KEY" | cut -d'.' -f2 | base64 -d 2>/dev/null | python3 -m json.tool # Look for: "iat": 1761135964 # Convert to human time: date -d @1761135964 # If iat is in the future, you've hit this bug
Fix 1: wait 10 minutes. Once the server clock catches up to the iat timestamp, the key becomes valid automatically. This is the easiest workaround.
Fix 2: sync the container clock. The root cause is clock drift between the Docker container and the host. Fix it:
# Check time inside the n8n container docker exec -it n8n date # If it differs from host time, sync the host NTP sudo timedatectl set-ntp true # Then restart the container docker restart n8n
Fix 3: regenerate the key after the clock is synced. The existing key’s iat is baked in — you must generate a new key after fixing the clock drift for the timestamp to be correct.
Section D: N8N_ENCRYPTION_KEY Mismatch: Credentials Silently Break After Update or Restart
This is the highest-impact, least-documented cause of “API key not recognized” in production. After a Docker container rebuild, an n8n version update, or a server migration, every stored credential silently stops working. The error in the execution log looks identical to a wrong API key:
Authorization failed - please check your credentials # or Credentials could not be decrypted. The likely reason is that a different 'encryptionKey' was used to encrypt the data.
What’s happening: n8n encrypts all stored credentials (API keys, passwords, OAuth tokens) using a key defined by N8N_ENCRYPTION_KEY. On first launch, if you don’t set this variable explicitly, n8n generates a random key and saves it to ~/.n8n/config. If that file disappears — because you rebuilt the Docker volume, migrated servers, or forgot to persist the .n8n directory — n8n generates a new random key. It can no longer decrypt the credentials stored with the old key. Every workflow that touches any credential will return 401 or “credentials could not be decrypted.”
How to prevent this? (do this before it happens)
# Generate a stable encryption key and save it NOW
openssl rand -hex 32
# Add to your .env file
N8N_ENCRYPTION_KEY=your_generated_64_char_hex_string
# In docker-compose.yml, set it explicitly
environment:
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
How to recover if it already happened?
- Find the old encryption key. Check
~/.n8n/configon the original host — it’s stored there as"encryptionKey": "...". If you have a backup of the.n8ndirectory, extract it from there. - Set that exact key as
N8N_ENCRYPTION_KEYin your environment and restart n8n. - If the old key is completely lost, there is no way to decrypt the stored credentials. You must recreate all credentials from scratch.
# Find the encryption key from a running container's config docker exec -it n8n cat /home/node/.n8n/config | grep encryptionKey # Or from a backed-up .n8n directory grep encryptionKey /path/to/backup/.n8n/config
EEFA note: In queue mode (multiple n8n workers), every worker and the main instance must load the identical
N8N_ENCRYPTION_KEYvalue. If even one worker has a different key, credentials will silently fail on that worker’s executions but work fine on others — making this extremely hard to diagnose.
Section E: Reading Real n8n Logs to Diagnose API Key Errors
Most developers check the n8n UI execution error and stop there. The real diagnostic information is in the container logs. Here’s how to read them and what to look for:
Enable verbose logging
# Add to your .env or docker-compose environment N8N_LOG_LEVEL=debug # Tail live logs docker logs -f n8n 2>&1 | grep -i "api\|auth\|401\|key\|credential"
What each log pattern means?
| Log line | What it means | Fix |
|---|---|---|
API key not recognized |
Header received but value doesn’t match stored key | Sections 1–4: verify key value, whitespace, reload env |
Unauthorized with no additional message |
Header is missing entirely — never reached auth middleware | Section 5: proxy stripping header, or wrong endpoint (Section B) |
Credentials could not be decrypted |
Encryption key mismatch after restart/migration | Section D: recover or reset N8N_ENCRYPTION_KEY |
Request failed with status code 401 inside a workflow node |
External API rejecting the credential n8n is sending | Section A: hidden characters, wrong auth method, plan limits |
iat set to future timestamp or token rejected immediately |
JWT clock drift bug | Section C: sync container clock, wait 10 min, regenerate key |
Section F: Verify the Fix: Confirm Your API Key Is Working
After applying any fix, don’t assume it worked – verify it with a direct test before updating your application code.
Minimal verification curl
# Replace with your actual instance URL and key
curl -s -o /dev/null -w "%{http_code}" \
-H "x-n8n-api-key: YOUR_KEY" \
https://your-n8n-instance.com/api/v1/workflows
# Expected output: 200
# If you see 401: key is wrong or not loaded
# If you see 404: you're hitting the wrong endpoint path
Verbose debug to see exactly what’s being sent
curl -v \ -H "x-n8n-api-key: YOUR_KEY" \ https://your-n8n-instance.com/api/v1/workflows 2>&1 | grep -E "^[><]" # Look for this line in output: # > x-n8n-api-key: YOUR_KEY # If that line is missing, your client isn't sending the header at all
Test through the proxy specifically
# Test DIRECT (bypassing proxy) curl -H "x-n8n-api-key: YOUR_KEY" http://localhost:5678/api/v1/workflows # Test VIA PROXY (through your domain) curl -H "x-n8n-api-key: YOUR_KEY" https://n8n.yourdomain.com/api/v1/workflows # If direct works but proxy fails → Section 5 (proxy stripping header)
9. Next Steps
- Securely store API keys – explore Vault, AWS Secrets Manager, or Docker secrets.
- Implement request retries with exponential back‑off for transient 401 errors.
- Monitor authentication failures via Grafana or Prometheus alerts.
Conclusion
The “API key not recognized” error is almost always a mismatch between the key stored in n8n and the header sent by the client. By verifying the exact key, ensuring the x-n8n-api-key header is correctly spelled and whitespace‑free, and restarting the service after any environment change, the issue disappears. Remember to forward the header through any reverse proxy and keep keys out of source control. Following the checklist and the proxy‑preservation tips guarantees reliable, production‑grade API access to n8n.



