Describe the problem/error/question
I have a self-hosted n8n Community Edition instance running on Windows 11 via Docker Desktop (plain docker run). My end goal is to build a Custom GPT (“N8NGPT”) that can interact with my local n8n via the REST API (list workflows, create workflows, patch/activate, etc.) so I can automate deployment and editing of workflows programmatically.
Despite many attempts and different authentication approaches, every request to GET /rest/workflows returns:
{“status”:“error”,“message”:“Unauthorized”}
I have tried:
-
Starting n8n with an environment API key (
N8N_API_KEY) passed viadocker run. -
Creating an API key in the n8n UI (Settings → n8n API) and using that UI key in requests.
-
Testing with
curl.exeon Windows,Invoke-RestMethodin PowerShell, and from a Linux curl container (curlimages/curl) to avoid Windows client quirks. -
Running without mounting any host volume (ephemeral container) to eliminate permission issues.
All attempts return HTTP 401. I’ve inspected docker logs and the instance shows normal startup and DB migrations, and netstat indicates port 5678 is listening. I’m stuck and asking whether this is a misconfiguration on my side, a Windows/Docker Desktop networking/header stripping problem, or a bug/behavior in n8n v1.112.4 where env/static keys and UI keys conflict.
What is the error message (if any)?
Primary API error (every request to /rest/* when providing a key):
{"status":"error","message":"Unauthorized"} (HTTP/1.1 401 Unauthorized)
Please share your workflow (if any)
None to share — I haven’t been able to create workflows via the API because POST /rest/workflows also returns 401. I did prepare an example “Hello World” JSON for testing, but import attempts were blocked by the auth failure.
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
Share the output returned by the last node
Information on your n8n setup
-
-
n8n version:
1.112.4(from container logs:Version: 1.112.4) -
Database: Default SQLite (the container ran migrations on startup; no external DB configured).
-
n8n EXECUTIONS_PROCESS setting: Default (no custom
EXECUTIONS_PROCESS/N8N_RUNNERS_ENABLEDset — running with default execution process). -
Running n8n via: Docker (plain
docker rununder Docker Desktop on Windows 11). -
Operating system (host): Windows 11 (Docker Desktop).
MORE INFO:
Hypothesized that the
N8N_API_KEYenv var vs UI key behavior might be clashing — recommended two safe paths:-
Start container without
N8N_API_KEYenv var and then create/use UI API key in the UI (recommended if you want UI-managed JWT-like keys). -
Or keep
N8N_API_KEYset and use that literal value as your API key for programmatic access (you lose per-key management via UI).COMMANDS/OUTPUTS:
- Test API from host using Windows curl
PS C:\Users\Suhaib Ahmed> curl.exe -H "X-N8N-API-KEY: firstkey123" http://localhost:5678/rest/workflows
-
-
Output:
{"status":"error","message":"Unauthorized"}
-
Verbose Windows curl test
PS C:\Users\Suhaib Ahmed> curl.exe -v -H "X-N8N-API-KEY: firstkey123" "http://localhost:5678/rest/workflows"Output (important parts):
> GET /rest/workflows HTTP/1.1 > Host: localhost:5678 > X-N8N-API-KEY: firstkey123 < HTTP/1.1 401 Unauthorized {"status":"error","message":"Unauthorized"} -
Run Linux curl inside container (curlimages/curl)
PS C:\Users\Suhaib Ahmed> docker run --rm curlimages/curl:latest -v -H "X-N8N-API-KEY: firstkey123" http://host.docker.internal:5678/rest/workflowsOutput (important parts):
* Established connection to host.docker.internal (192.168.65.254 port 5678) > GET /rest/workflows HTTP/1.1 > X-N8N-API-KEY: firstkey123 < HTTP/1.1 401 Unauthorized {"status":"error","message":"Unauthorized"} -
Inspected env var inside container
PS C:\Users\Suhaib Ahmed> docker exec -it n8n printenv | findstr N8N_API_KEY
Output:
N8N_API_KEY=firstkey123
-
Tried curl inside container (failed: no curl installed)
PS C:\Users\Suhaib Ahmed> docker exec -it n8n curl -H "X-N8N-API-KEY: firstkey123" http://localhost:5678/rest/workflows
Output:
OCI runtime exec failed: exec failed: unable to start container process: exec: "curl": executable file not found in $PATH: unknown
-
Tested with PowerShell Invoke-RestMethod
PS C:\Users\Suhaib Ahmed> Invoke-RestMethod -Uri "http://localhost:5678/rest/workflows" ` -Method Get ` -Headers @{"X-N8N-API-KEY"="firstkey123"} ` -Proxy $null -Verbose
Output:
VERBOSE: GET with 0-byte payload
Invoke-RestMethod : {"status":"error","message":"Unauthorized"}
...
-
A. Used JWT-style API key (from UI)
PS C:\Users\Suhaib Ahmed> docker run --rm curlimages/curl:latest -v -H "X-N8N-API-KEY: <REDACTED_UI_KEY>" http://host.docker.internal:5678/rest/workflowsOutput:
< HTTP/1.1 401 Unauthorized {"status":"error","message":"Unauthorized"}PS C:\Users\Suhaib Ahmed> curl.exe -H "X-N8N-API-KEY: <REDACTED_UI_KEY>" "http://localhost:5678/rest/workflows"Output:
{"status":"error","message":"Unauthorized"} -
B. Tried again with new UI key
PS C:\Users\Suhaib Ahmed> docker run --rm curlimages/curl:latest -v -H "X-N8N-API-KEY: <REDACTED_NEW_UI_KEY>" http://host.docker.internal:5678/rest/workflowsOutput:
< HTTP/1.1 401 Unauthorized {"status":"error","message":"Unauthorized"} -
Container logs
PS C:\Users\User> docker logs n8nOutput (important parts):
Initializing n8n process n8n ready on ::, port 5678 Migrations in progress, please do NOT stop the process. ... Editor is now accessible via: http://localhost:5678 Owner was set up successfully User survey updated successfully [license SDK] license successfully activated
IN ESSENCE:
I have tried:
-
Starting n8n with an environment API key (
N8N_API_KEY) passed viadocker run. -
Creating an API key in the n8n UI (Settings → n8n API) and using that UI key in requests.
-
Testing with
curl.exeon Windows,Invoke-RestMethodin PowerShell, and from a Linux curl container (curlimages/curl) to avoid Windows client quirks. -
Running without mounting any host volume (ephemeral container) to eliminate permission issues.
All attempts return HTTP 401
Any help would be massively appreciated
, I’ve put in hours to fix this but to no avail ![]()