name: n8n-rest-api-session-cookie-auth
description: "n8n v2.9.x — Authenticate via session cookie and create/activate workflows via REST API using Python"
n8n REST API — Session Cookie Authentication (v2.9.x)
Context
n8n v2.9.x REST API uses session-based authentication, NOT API key for most operations. The API key (X-N8N-API-KEY header) requires the API to be explicitly enabled in settings. Session cookie auth works reliably.
Authentication Flow
`python
import urllib.request, urllib.error, http.cookiejar, json
N8N_URL = 'https://your-n8n.example.com'
EMAIL = 'your@email.com'
PASSWORD = 'your-password'
COOKIE_FILE = '/tmp/n8n_cookies.txt'
1. Login and save session cookie
jar = http.cookiejar.MozillaCookieJar(COOKIE_FILE)
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
req = urllib.request.Request(
f'{N8N_URL}/rest/login',
data=json.dumps({
'emailOrLdapLoginId': EMAIL,
'password': PASSWORD
}).encode(),
headers={'Content-Type': 'application/json'},
method='POST'
)
resp = opener.open(req, timeout=15)
data = json.loads(resp.read())
print(f"Logged in as: {data['data']['email']}")
jar.save()
2. Use session cookie for subsequent API calls
jar.load() # reload cookies
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
Example: list workflows
req2 = urllib.request.Request(
f'{N8N_URL}/rest/workflows?limit=100',
headers={'Content-Type': 'application/json'}
)
resp2 = opener.open(req2, timeout=15)
workflows = json.loads(resp2.read())
for w in workflows['data']:
print(f"{w['id']} - {w['name']} (active:{w['active']})")
`
Create Workflow via REST API
`python
workflow = {
"name": "My Workflow",
"nodes": [...],
"connections": {...},
"settings": {"executionOrder": "v1"},
"active": False,
"tags": []
}
req = urllib.request.Request(
f'{N8N_URL}/rest/workflows',
data=json.dumps(workflow).encode(),
headers={'Content-Type': 'application/json'},
method='POST'
)
resp = opener.open(req, timeout=20)
wf = json.loads(resp.read())
print(f"Created: {wf['id']}, versionId: {wf['versionId']}")
`
Activate Workflow
`python
Activate requires versionId from the created workflow
VERSION_ID = wf['versionId'] # e.g. '1b536c63-dc4c-46ec-a76f-1791e74c467a'
req = urllib.request.Request(
f'{N8N_URL}/rest/workflows/{WF_ID}/activate',
data=json.dumps({"versionId": VERSION_ID}).encode(),
headers={'Content-Type': 'application/json'},
method='POST'
)
Note: This may return 400 if workflow hasn't been "saved" in UI first
If activation fails, open workflow in UI and click Activate manually
`
Known Issues
"Active version not found" after DB INSERT
If you insert a workflow directly into workflow_entity table, n8n won't recognize it because:
- -
workflow_published_versiontable needs an entry linkingworkflowId→publishedVersionId - -
shared_workflowtable needs an entry linkingworkflowId→projectId
Fix: Create workflow via POST /rest/workflows instead of DB INSERT.
API key (X-N8N-API-KEY) returns 401
n8n v2.9.x requires API key to be explicitly enabled. Session cookie auth is more reliable. To create an API key:
`sql
-- n8n stores API keys hashed in user_api_keys table
INSERT INTO user_api_keys (id, "userId", label, "apiKey", "createdAt", "updatedAt", scopes, audience)
VALUES (
gen_random_uuid()::text,
(SELECT id FROM "user" LIMIT 1)::uuid,
'My Key',
'n8n_' || gen_random_bytes(24)::text, -- hash stored, not plain text
NOW(), NOW(),
'[]'::json,
'*'
);
`
Note: n8n stores SHA-256 hash of API key, not plain text. The plain text key shown to user once must be saved immediately.
Cookie jar format
Use http.cookiejar.MozillaCookieJar — n8n session cookies are in Netscape/Mozilla format.
Database Tables (n8n v2.9.x)
| Table | Purpose |
| ------- | --------- |
workflow_entity | Workflows (id, name, nodes JSONB, connections JSONB, active, settings JSONB, versionId) |
webhook_entity | Registered webhooks (webhookPath, method, workflowId, webhookId) |
shared_workflow | Project assignments (workflowId, projectId, role) |
user_api_keys | API keys (userId, apiKey hash, label) |
project | Projects (id, name, type) |
Key n8n CLI Commands (Docker)
`bash
Restart n8n container
docker restart n8n
n8n version
docker exec n8n node --version
Reset user password (creates new owner account)
docker exec n8n n8n user-management:reset
Run SQL queries
docker exec -i n8n-postgres psql -U n8n -d n8n -c 'SELECT ...'
`