📄 SKILL.md

← Vault

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:

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)

TablePurpose
----------------
workflow_entityWorkflows (id, name, nodes JSONB, connections JSONB, active, settings JSONB, versionId)
webhook_entityRegistered webhooks (webhookPath, method, workflowId, webhookId)
shared_workflowProject assignments (workflowId, projectId, role)
user_api_keysAPI keys (userId, apiKey hash, label)
projectProjects (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 ...'

`