The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "User Authentication & Session Management",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "auth/login",
"responseMode": "onReceived",
"options": {}
},
"id": "auth-login-trigger-001",
"name": "Authentication Request",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
]
},
{
"parameters": {
"language": "javaScript",
"jsCode": "// Parse and validate authentication request\nconst requestBody = $json.body || {};\nconst { username, password, email, authType = 'credentials' } = requestBody;\n\n// Validation\nif (authType === 'credentials') {\n if (!username || !password) {\n throw new Error('Username and password are required');\n }\n} else if (authType === 'oauth') {\n if (!email) {\n throw new Error('Email is required for OAuth authentication');\n }\n}\n\n// Extract client information\nconst clientInfo = {\n userAgent: $json.headers['user-agent'] || '',\n ipAddress: $json.headers['x-forwarded-for'] || $json.headers['x-real-ip'] || 'unknown',\n language: $json.headers['accept-language']?.split(',')[0] || 'en-US',\n timestamp: new Date().toISOString()\n};\n\nreturn {\n json: {\n authRequest: {\n username,\n password,\n email,\n authType\n },\n clientInfo,\n requestId: `auth_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n }\n};"
},
"id": "parse-auth-request-002",
"name": "Parse Authentication Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, username, email, password_hash, role, status, preferences, voice_profile_id FROM users WHERE username = $1 OR email = $1;",
"options": {
"queryParameters": "={{ $json.authRequest.username || $json.authRequest.email }}"
}
},
"id": "lookup-user-003",
"name": "Lookup User",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
680,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"language": "javaScript",
"jsCode": "// Verify user credentials\nconst authRequest = $('Parse Authentication Request').item.json.authRequest;\nconst userData = $input.all()[0]?.json || null;\n\nif (!userData) {\n return {\n json: {\n authResult: 'user_not_found',\n success: false,\n message: 'Invalid credentials'\n }\n };\n}\n\n// Check account status\nif (userData.status !== 'active') {\n return {\n json: {\n authResult: 'account_disabled',\n success: false,\n message: 'Account is disabled'\n }\n };\n}\n\n// Verify password for credential-based auth (simplified version)\nif (authRequest.authType === 'credentials') {\n // In real implementation, use bcrypt or similar\n // This is a simplified check for demo purposes\n const isValidPassword = true; // Replace with actual bcrypt comparison\n \n if (!isValidPassword && authRequest.password !== 'demo') {\n return {\n json: {\n authResult: 'invalid_password',\n success: false,\n message: 'Invalid credentials'\n }\n };\n }\n}\n\n// Successful authentication\nreturn {\n json: {\n authResult: 'success',\n success: true,\n user: {\n id: userData.id,\n username: userData.username,\n email: userData.email,\n role: userData.role || 'user',\n preferences: userData.preferences || {},\n voice_profile_id: userData.voice_profile_id\n }\n }\n};"
},
"id": "verify-credentials-004",
"name": "Verify Credentials",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.success }}",
"operation": "equal",
"value2": true
}
]
}
},
"id": "check-auth-success-005",
"name": "Check Authentication Success",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1120,
300
]
},
{
"parameters": {
"language": "javaScript",
"jsCode": "// Generate JWT tokens and create session\nconst user = $json.user;\nconst clientInfo = $('Parse Authentication Request').item.json.clientInfo;\nconst requestId = $('Parse Authentication Request').item.json.requestId;\n\n// Generate session data\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\nconst accessToken = `access_${Date.now()}_${Math.random().toString(36).substr(2, 16)}`;\nconst refreshToken = `refresh_${Date.now()}_${Math.random().toString(36).substr(2, 16)}`;\n\n// Session expiry times\nconst now = new Date();\nconst accessTokenExpiry = new Date(now.getTime() + 15 * 60 * 1000); // 15 minutes\nconst refreshTokenExpiry = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 7 days\nconst sessionExpiry = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours\n\nconst sessionData = {\n session_id: sessionId,\n user_id: user.id,\n access_token: accessToken,\n refresh_token: refreshToken,\n access_expires: accessTokenExpiry.toISOString(),\n refresh_expires: refreshTokenExpiry.toISOString(),\n session_expires: sessionExpiry.toISOString(),\n client_info: clientInfo,\n created_at: now.toISOString(),\n last_activity: now.toISOString(),\n status: 'active'\n};\n\n// Response data\nconst authResponse = {\n success: true,\n user: {\n id: user.id,\n username: user.username,\n email: user.email,\n role: user.role,\n preferences: user.preferences,\n voice_profile_id: user.voice_profile_id\n },\n session: {\n session_id: sessionId,\n access_token: accessToken,\n refresh_token: refreshToken,\n expires_in: 15 * 60, // 15 minutes in seconds\n token_type: 'Bearer'\n },\n permissions: {\n voice_interactions: true,\n analytics_view: user.role === 'admin' || user.role === 'analyst',\n user_management: user.role === 'admin',\n training_management: user.role === 'admin'\n }\n};\n\nreturn {\n json: {\n sessionData,\n authResponse\n }\n};"
},
"id": "create-session-006",
"name": "Create Session",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
240
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO user_sessions (session_id, user_id, access_token, refresh_token, access_expires, refresh_expires, session_expires, client_info, status, created_at, last_activity) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
"options": {
"queryParameters": "={{ $json.sessionData.session_id }},{{ $json.sessionData.user_id }},{{ $json.sessionData.access_token }},{{ $json.sessionData.refresh_token }},{{ $json.sessionData.access_expires }},{{ $json.sessionData.refresh_expires }},{{ $json.sessionData.session_expires }},{{ JSON.stringify($json.sessionData.client_info) }},{{ $json.sessionData.status }},{{ $json.sessionData.created_at }},{{ $json.sessionData.last_activity }}"
}
},
"id": "store-session-007",
"name": "Store Session",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1560,
240
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO auth_logs (user_id, username, auth_result, ip_address, user_agent, timestamp, request_id) VALUES ($1, $2, $3, $4, $5, $6, $7)",
"options": {
"queryParameters": "={{ $('Verify Credentials').item.json.user?.id || null }},{{ $('Parse Authentication Request').item.json.authRequest.username }},{{ $('Verify Credentials').item.json.authResult }},{{ $('Parse Authentication Request').item.json.clientInfo.ipAddress }},{{ $('Parse Authentication Request').item.json.clientInfo.userAgent }},{{ new Date().toISOString() }},{{ $('Parse Authentication Request').item.json.requestId }}"
}
},
"id": "log-auth-attempt-008",
"name": "Log Authentication Attempt",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1780,
240
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $('Create Session').item.json.authResponse }}"
},
"id": "success-response-009",
"name": "Success Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
2000,
240
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO auth_logs (username, auth_result, ip_address, user_agent, timestamp, request_id, error_message) VALUES ($1, $2, $3, $4, $5, $6, $7)",
"options": {
"queryParameters": "={{ $('Parse Authentication Request').item.json.authRequest.username }},{{ $('Verify Credentials').item.json.authResult }},{{ $('Parse Authentication Request').item.json.clientInfo.ipAddress }},{{ $('Parse Authentication Request').item.json.clientInfo.userAgent }},{{ new Date().toISOString() }},{{ $('Parse Authentication Request').item.json.requestId }},{{ $('Verify Credentials').item.json.message }}"
}
},
"id": "log-failed-attempt-010",
"name": "Log Failed Attempt",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
1340,
400
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": false,\n \"error\": {\n \"code\": \"AUTHENTICATION_FAILED\",\n \"message\": \"{{ $('Verify Credentials').item.json.message }}\",\n \"timestamp\": \"{{ new Date().toISOString() }}\"\n }\n}",
"options": {
"responseCode": 401
}
},
"id": "error-response-011",
"name": "Error Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1560,
400
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "auth/logout",
"responseMode": "onReceived",
"options": {}
},
"id": "logout-trigger-012",
"name": "Logout Request",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
600
]
},
{
"parameters": {
"language": "javaScript",
"jsCode": "// Parse logout request\nconst authHeader = $json.headers.authorization || '';\nconst token = authHeader.replace('Bearer ', '');\n\nif (!token) {\n throw new Error('Authorization token is required');\n}\n\nreturn {\n json: {\n token,\n timestamp: new Date().toISOString()\n }\n};"
},
"id": "parse-logout-request-013",
"name": "Parse Logout Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
600
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "UPDATE user_sessions SET status = 'terminated', terminated_at = $1 WHERE access_token = $2 AND status = 'active';",
"options": {
"queryParameters": "={{ new Date().toISOString() }},{{ $json.token }}"
}
},
"id": "terminate-session-014",
"name": "Terminate Session",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
680,
600
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"message\": \"Successfully logged out\",\n \"timestamp\": \"{{ new Date().toISOString() }}\"\n}"
},
"id": "logout-response-015",
"name": "Logout Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
900,
600
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 1
}
]
}
},
"id": "session-cleanup-trigger-016",
"name": "Session Cleanup Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
900
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "DELETE FROM user_sessions WHERE session_expires < NOW() OR (status = 'terminated' AND terminated_at < NOW() - INTERVAL '7 days');",
"options": {}
},
"id": "cleanup-expired-sessions-017",
"name": "Cleanup Expired Sessions",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
460,
900
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Authentication Request": {
"main": [
[
{
"node": "Parse Authentication Request",
"type": "main",
"index": 0
}
]
]
},
"Parse Authentication Request": {
"main": [
[
{
"node": "Lookup User",
"type": "main",
"index": 0
}
]
]
},
"Lookup User": {
"main": [
[
{
"node": "Verify Credentials",
"type": "main",
"index": 0
}
]
]
},
"Verify Credentials": {
"main": [
[
{
"node": "Check Authentication Success",
"type": "main",
"index": 0
}
]
]
},
"Check Authentication Success": {
"main": [
[
{
"node": "Create Session",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Failed Attempt",
"type": "main",
"index": 0
}
]
]
},
"Create Session": {
"main": [
[
{
"node": "Store Session",
"type": "main",
"index": 0
}
]
]
},
"Store Session": {
"main": [
[
{
"node": "Log Authentication Attempt",
"type": "main",
"index": 0
}
]
]
},
"Log Authentication Attempt": {
"main": [
[
{
"node": "Success Response",
"type": "main",
"index": 0
}
]
]
},
"Log Failed Attempt": {
"main": [
[
{
"node": "Error Response",
"type": "main",
"index": 0
}
]
]
},
"Logout Request": {
"main": [
[
{
"node": "Parse Logout Request",
"type": "main",
"index": 0
}
]
]
},
"Parse Logout Request": {
"main": [
[
{
"node": "Terminate Session",
"type": "main",
"index": 0
}
]
]
},
"Terminate Session": {
"main": [
[
{
"node": "Logout Response",
"type": "main",
"index": 0
}
]
]
},
"Session Cleanup Trigger": {
"main": [
[
{
"node": "Cleanup Expired Sessions",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true
},
"staticData": null,
"tags": [
"authentication",
"session",
"security"
],
"triggerCount": 3,
"updatedAt": "2025-06-27T00:00:00.000Z",
"versionId": "2.0"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
User Authentication & Session Management. Uses postgres. Webhook trigger; 17 nodes.
Source: https://github.com/161sam/n8n-voice-ai/blob/main/workflows/User-Authentication-Session-Management.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Suspicious_login_detection. Uses postgres, httpRequest, noOp, html. Webhook trigger; 43 nodes.
This n8n workflow is designed for security monitoring and incident response when suspicious login events are detected. It can be initiated either manually from within the n8n UI for testing or automat
Workflow1-2-3. Uses httpRequest, gmail, telegram, postgres. Webhook trigger; 34 nodes.
email-handler-new. Uses gmail, gmailTrigger, postgres. Webhook trigger; 10 nodes.
Order-Workflow. Uses gmail, postgres, openAi. Webhook trigger; 7 nodes.