Workflow: Suspicious_login_detection
Integrations: code, gmail, html, httpRequest, if, manualTrigger, merge, noOp, postgres, set, slack, stickyNote, switch, webhook

{"id": "xQHiKDTkezDY5lFu", "meta": {"instanceId": "workflow-65a7b221", "versionId": "1.0.0", "createdAt": "2025-09-29T07:07:51.441235", "updatedAt": "2025-09-29T07:07:51.441301", "owner": "n8n-user", "license": "MIT", "category": "automation", "status": "active", "priority": "high", "environment": "production"}, "name": "Suspicious_login_detection", "tags": ["automation", "n8n", "production-ready", "excellent", "optimized"], "nodes": [{"id": "a95e464a-7451-4737-9db8-993a6568595b", "name": "Extract relevant data", "type": "n8n-nodes-base.set", "position": [-260, 700], "parameters": {"values": {"string": [{"name": "ip", "value": "={{ $json.body.context.ip }}"}, {"name": "userAgent", "value": "={{ $json.body.context.userAgent }}"}, {"name": "timestamp", "value": "={{ $json.body.originalTimestamp }}"}, {"name": "url", "value": "={{ $json.body.context.page.url }}"}, {"name": "userId", "value": "={{ $json.body.userId }}"}]}, "options": {}, "keepOnlySet": true}, "typeVersion": 2, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "d7dea680-14f3-4ffd-bfaf-f928b69d801d", "name": "New /login event", "type": "n8n-nodes-base.webhook", "disabled": true, "position": [-740, 700], "webhookId": "705ca4c4-0a38-4ef8-9de9-abc8b3686dc6", "parameters": {"path": "705ca4c4-0a38-4ef8-9de9-abc8b3686dc6", "options": {}, "httpMethod": "POST"}, "typeVersion": 1, "notes": "This webhook node performs automated tasks as part of the workflow."}, {"id": "bd75aad9-2d24-4083-823d-bc789fb7ef07", "name": "Unknown threat?", "type": "n8n-nodes-base.if", "position": [720, 1240], "parameters": {"conditions": {"boolean": [{"value1": "={{ $json.noise }}"}, {"value1": "={{ $json.riot }}"}]}}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "d0845980-3b8c-4659-95a1-82e925867f28", "name": "Get last 10 logins from the same user", "type": "n8n-nodes-base.postgres", "disabled": true, "position": [960, 1220], "parameters": {"query": "SELECT * FROM staging_n8n_cloud_frontend.user_signed_in WHERE user_id='{{ $('Extract relevant data').item.json.userId }}' ORDER BY received_at DESC LIMIT 10;", "options": {}, "operation": "executeQuery"}, "credentials": {"postgres": {"id": "aP9LLonHicGm2A7j", "name": "n8n product data"}}, "typeVersion": 2.2, "notes": "This postgres node performs automated tasks as part of the workflow."}, {"id": "90e859b2-aa64-48e7-a8fe-696e3b7216f1", "name": "Query IP API1", "type": "n8n-nodes-base.httpRequest", "position": [1240, 1340], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {}}, "typeVersion": 4.1, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "3a944973-132a-4272-97e3-42528eb4c0fc", "name": "New location?", "type": "n8n-nodes-base.if", "position": [1440, 1340], "parameters": {"conditions": {"string": [{"value1": "={{ $json.city }}", "value2": "={{ $('Merge').item.json.city }}", "operation": "notEqual"}]}}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "fb4d5d07-58ae-4b17-a389-29e7fbe2caa2", "name": "Parse User Agent", "type": "n8n-nodes-base.httpRequest", "position": [1260, 1640], "parameters": {"url": "{{ $env.API_BASE_URL }}", "options": {}, "sendQuery": true, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpQueryAuth", "queryParameters": {"parameters": [{"name": "ua", "value": "={{ $json.context_user_agent }}"}]}}, "credentials": {"httpQueryAuth": {"id": "33f1NrH1bLdXCGyw", "name": "n8n Userparser API Key"}}, "typeVersion": 4.1, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "56442924-914c-461d-b4d7-f08192e1b53b", "name": "Merge", "type": "n8n-nodes-base.merge", "position": [295, 1502], "parameters": {"mode": "combine", "options": {}, "combinationMode": "multiplex"}, "typeVersion": 2.1, "notes": "This merge node performs automated tasks as part of the workflow."}, {"id": "2b36f782-029d-41de-8823-6c083f3c305a", "name": "New Device/Browser?", "type": "n8n-nodes-base.if", "position": [1460, 1640], "parameters": {"conditions": {"string": [{"value1": "={{ $json.browser.name }}", "value2": "={{ $('Complete login info').first().json.browser.name }}", "operation": "notEqual"}, {"value1": "={{ $json.operatingSystem.name }}", "value2": "={{ $('Complete login info').first().json.operatingSystem.name }}", "operation": "notEqual"}, {"value1": "={{ $json.device.type }}", "value2": "={{ $('Complete login info').first().json.device.type }}", "operation": "notEqual"}]}, "combineOperation": "any"}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "612c3704-6ea1-4978-ae84-17326f459c25", "name": "Complete login info", "type": "n8n-nodes-base.merge", "position": [540, 1240], "parameters": {"mode": "combine", "options": {}, "combinationMode": "multiplex"}, "typeVersion": 2.1, "notes": "This merge node performs automated tasks as part of the workflow."}, {"id": "9c097c31-a86d-45fe-92c7-14a58eae87b4", "name": "Query user by ID", "type": "n8n-nodes-base.postgres", "disabled": true, "position": [2020, 1340], "parameters": {"query": "SELECT * FROM staging_n8n_cloud_frontend.users WHERE id='{{ $('Extract relevant data').item.json.userId }}'", "options": {}, "operation": "executeQuery"}, "credentials": {"postgres": {"id": "aP9LLonHicGm2A7j", "name": "n8n product data"}}, "typeVersion": 2.2, "notes": "This postgres node performs automated tasks as part of the workflow."}, {"id": "cd6fb55b-b8f6-4778-a62a-34be42e2660d", "name": "New Location", "type": "n8n-nodes-base.noOp", "position": [1660, 1280], "parameters": {}, "executeOnce": true, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}, {"id": "7070a43a-d588-4bbb-b8d0-50e8eff171df", "name": "New Device/Browser", "type": "n8n-nodes-base.noOp", "position": [1674, 1625], "parameters": {}, "executeOnce": true, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}, {"id": "dca6d5ed-d92f-49a6-9910-c9194e696e70", "name": "User has email?", "type": "n8n-nodes-base.if", "position": [2360, 1360], "parameters": {"conditions": {"string": [{"value1": "={{ $json.email }}", "operation": "isNotEmpty"}]}}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "14cd3d37-5c00-4750-8ad2-f78fce66019c", "name": "HTML", "type": "n8n-nodes-base.html", "position": [2580, 1313], "parameters": {"html": "<p>\n  Hello {{ $json.first_name || $json.username }},\n</p>\n<p>\n  We've detected a recent login to your n8n account from a new device or location. Here are the details:\n</p>\n<p>\n  <ul>\n    <li><b>Username:</b> {{ $json.username }}</li>\n    <li><b>Date & Time:</b> {{ $('Extract relevant data').item.json.timestamp }}</li>\n    <li><b>Location:</b> {{ $('Complete login info').item.json.city }}, {{ $('Complete login info').item.json.country }}</li>\n    <li><b>Device:</b> {{ $('Complete login info').item.json.operatingSystem.name }} ({{ $('Complete login info').item.json.device.type }})</li>\n  </ul>\n</p>\n<p>\n  If this was you, you can disregard this email. We just wanted to make sure it was you who logged in from a new device or location.\n</p>\n  If this wasn't you, we recommend resetting your password right away.\n</p>\n\n<style>\n  p {\n    font-family: sans-serif;\n  }\n</style>"}, "typeVersion": 1, "notes": "This html node performs automated tasks as part of the workflow."}, {"id": "e99f7779-9b84-4f8c-80a0-b34c3c9df5b4", "name": "Inform user", "type": "n8n-nodes-base.gmail", "disabled": true, "position": [2740, 1313], "parameters": {"sendTo": "={{ $('User has email?').item.json.email }}", "message": "={{ $json.html }}", "options": {}, "subject": "Important: Usual Login Attempt Detected"}, "credentials": {"gmailOAuth2": {"id": "{{ $credentials.gmailOAuth2.id }}", "name": "Gmail - milorad@n8n.io"}}, "typeVersion": 2, "notes": "This gmail node performs automated tasks as part of the workflow."}, {"id": "b280b287-7b20-4dcb-9c0a-a3e5c3a60771", "name": "noise?", "type": "n8n-nodes-base.if", "position": [340, 220], "parameters": {"conditions": {"boolean": [{"value1": "={{ $json.noise }}", "value2": true}]}}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "5be949da-f04a-44f9-9cf0-5e221f9d27e8", "name": "Slack", "type": "n8n-nodes-base.slack", "disabled": true, "position": [1560, 500], "parameters": {"text": "=Suspicious login attempt detected:\n  - Priority: {{ $json.priority }}\n  - User: {{ $('Extract relevant data').item.json[\"userId\"] }}\n  - IP: {{ $('Extract relevant data').item.json[\"ip\"] }}\n  - Timestamp: {{ $('Extract relevant data').item.json[\"timestamp\"] }}\n  - User Agent: {{ $('Extract relevant data').item.json[\"userAgent\"] }}\nGreyNoise report: {{ $env.WEBHOOK_URL }}{{ $('Extract relevant data').item.json[\"ip\"] }}", "select": "channel", "channelId": {"__rl": true, "mode": "name", "value": "#slack-message-test"}, "otherOptions": {}}, "credentials": {"slackApi": {"id": "{{ $credentials.slackApi.id }}", "name": "n8n Slack"}}, "typeVersion": 2, "notes": "This slack node performs automated tasks as part of the workflow."}, {"id": "241e492c-fb9a-4b93-bd76-4167cb67f212", "name": "Check trust level", "type": "n8n-nodes-base.switch", "position": [780, 360], "parameters": {"rules": {"rules": [{"output": 3, "value2": 1, "operation": "equal"}, {"output": 2, "value2": 2, "operation": "equal"}]}, "value1": "={{ $json.trust_level }}", "fallbackOutput": 1}, "typeVersion": 1, "notes": "This switch node performs automated tasks as part of the workflow."}, {"id": "f99741d0-161e-49c6-8e41-d61b080e977d", "name": "Check classification", "type": "n8n-nodes-base.switch", "position": [780, 200], "parameters": {"rules": {"rules": [{"value2": "malicious"}, {"output": 2, "value2": "benign"}, {"output": 1, "value2": "unknown"}]}, "value1": "={{ $json.classification }}", "dataType": "string"}, "typeVersion": 1, "notes": "This switch node performs automated tasks as part of the workflow."}, {"id": "594857f6-713f-496e-8257-b74acf5d1282", "name": "Sticky Note2", "type": "n8n-nodes-base.stickyNote", "position": [0.10300782209924364, -502.1236093865191], "parameters": {"width": 1443.8164871528645, "height": 1185.151137495839, "content": "![greynoise]({{ $env.WEBHOOK_URL }}\n## \ud83d\udea6 Advanced Threat Prioritization with GreyNoise Data\n\nIn this section of the workflow, the integration of GreyNoise data, particularly in the `GreyNoise` node, plays a pivotal role in refining the threat prioritization process. This node's interaction with GreyNoise ensures that each alert is given an appropriate level of attention, based on the nature of the IP address involved.\n\n-   **GreyNoise Analysis for Inbound Threats:** When the `GreyNoise` node identifies an IP address, it queries GreyNoise, considering both NOISE and RIOT datasets ([More here]({{ $env.WEBHOOK_URL }} The response from this node guides the subsequent steps:\n    -   **High Priority for Unknown IPs:** The `Check trust level` and `Check classification` nodes act here. If GreyNoise has no data on the IP (noise:false, riot:false), the priority is set high in the `\ud83d\udd34 Priority: HIGH` node. This indicates a potential targeted attack, requiring immediate analyst review.\n    -   **Low to Medium Priority for Common Business Services:** IPs identified as part of common business services (riot:true), depending on their trust level and operation status, are assigned low to medium priority by the `\ud83d\udfe1 Priority: MEDIUM` and `\ud83d\udfe2 Priority: LOW` nodes. This reflects a lower risk of malicious activity.\n-   **Classification-Based Prioritization:** The workflow also considers the GreyNoise classification of the IP (malicious, benign, unknown) in the `Check classification` node:\n    -   **Malicious IPs:** Medium-high priority, suggesting opportunistic but potentially harmful activity, set in the `\ud83d\udd34 Priority: HIGH` node.\n    -   **Benign IPs:** Low priority, as these are usually harmless scans by known actors, designated in the `\ud83d\udfe2 Priority: LOW` node.\n    -   **Unknown IPs:** Low-medium priority, indicating possibly innocuous but unverified activity, managed by the `\ud83d\udfe1 Priority: MEDIUM` node.\n-   **Additional Context for Outbound Threats:** For outbound connections, the workflow prioritizes alerts based on whether the IP is a known service provider or a known device scanning the internet, as interpreted by the `GreyNoise` node. High priority is assigned to outbound connections to scanning devices in the `\ud83d\udd34 Priority: HIGH` node, indicating potentially unwanted behavior.\n\n\nThis approach, leveraging GreyNoise's advanced data analytics, showcases n8n's capability to deliver sophisticated cybersecurity solutions. By integrating this intelligent prioritization mechanism, the workflow ensures that your security team focuses on the most pressing threats first, enhancing overall security posture.\n\n### Authentication - No Free Tier Available\n\nTo set your API key for GreyNoise, open the `GreyNoise` node, and add a new authentication credential. Choose `Generic Credential Type` then `Header Auth`. Lastly, under `Credential for Header Auth` set the name to `key` and value to your `api key`."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "ee90c638-882d-4a2e-8164-adaf4ec386be", "name": "Sticky Note3", "type": "n8n-nodes-base.stickyNote", "position": [1450.4432083435722, -139], "parameters": {"width": 560.0194854548777, "height": 818.6128004838087, "content": "![Slack]({{ $env.WEBHOOK_URL }}\n## \ud83d\udce2 Slack Notification for Alert Dissemination\n\nThe `Slack` node plays a crucial role in alert communication. It ensures that once a threat is identified and prioritized, the relevant information is quickly disseminated to your security team via Slack.\n\n-   **Timely Alert Notifications:** The `Slack` node is configured to send detailed alerts to a specified Slack channel. These alerts include critical information such as the priority level, user ID, IP address, timestamp, and user agent of the suspicious login attempt. It ensures that your team is promptly informed about potential threats, allowing for quick action to mitigate risks.\n-   **Integration of Data from Previous Nodes:** This node adeptly utilizes data extracted and processed by earlier nodes like `Extract relevant data`. It enriches the Slack message with this detailed information, providing a comprehensive overview of the threat.\n-   **Direct Link to GreyNoise Analysis:** Additionally, the Slack message includes a direct link to the GreyNoise visualization for the IP in question. This link, crafted using data from the `Extract relevant data` node, allows team members to quickly access in-depth information about the IP, facilitating a faster and more informed response.\n\n\nThis approach demonstrates n8n's ability to integrate seamlessly with communication tools like Slack, ensuring that cybersecurity teams are always informed and ready to respond to threats efficiently."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "b617da5f-f7e0-4c6d-8080-c1d4b2e2ed53", "name": "Sticky Note4", "type": "n8n-nodes-base.stickyNote", "position": [477, 690], "parameters": {"width": 696.8700988949365, "height": 894.3487921624444, "content": "![postgre]({{ $env.WEBHOOK_URL }}\n## \ud83d\udd04  Synthesizing Data for Comprehensive Analysis\nThe `Complete login info` node serves as a crucial juncture, integrating data from multiple sources for a detailed analysis of each login attempt.\n\n-   **Combining Multiple Data Streams:** The `Complete login info` node merges information from the `GreyNoise`, `IP API`, and `UserParser` nodes. This process creates a comprehensive dataset by combining threat intelligence from GreyNoise, geolocation details from IP-API, and user agent information from UserParser.\n-   **Enhanced Context for Security Analysis:** By amalgamating data from these varied sources, the workflow gains a multi-faceted view of each login attempt. This enriched context is essential for identifying potential security threats with higher precision.\n-   **Efficient Workflow Structure:** The integration of these diverse data points exemplifies n8n's efficiency in managing complex workflows. By funneling various streams of information into a single node, the workflow ensures that all relevant data is considered in unison during the analysis phase.\n-   **Informing Subsequent Workflow Steps:** The dataset prepared by the `Complete login info` node lays the groundwork for further steps in the workflow. It provides the necessary context for nodes that follow, such as the `Unknown threat?` and `Get last 10 logins from the same user` nodes, to make informed decisions based on a holistic view of the login event."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "1e106297-b7db-4b2d-b08c-a35880782c8c", "name": "Sticky Note5", "type": "n8n-nodes-base.stickyNote", "position": [1185, 691], "parameters": {"width": 663.6738255654103, "height": 892.4220900613532, "content": "![ipapi]({{ $env.WEBHOOK_URL }}\n## \ud83d\udccd Assessing Login Location Anomalies\n\nThe nodes following `Get last 10 logins from the same user` are dedicated to analyzing login location patterns to identify any anomalies.\n\n-   **Fetching Historical Login Data:** The `Get last 10 logins from the same user` node queries a Postgres database to retrieve the last 10 login records for a user. This data forms the baseline for identifying unusual login locations.\n\n-   **Comparing Current and Historical Geolocation Data:** The `Query IP API1` node fetches the geolocation data for the current login attempt. This data is then compared with historical login locations in the `New location?` node.\n\n-   **Identifying Location Anomalies:** The `New location?` node checks if the city from the current login is different from the cities in the user's login history. This comparison is crucial to detect any unusual login patterns, such as logins from new, potentially suspicious locations.\n\n-   **Routing Based on Location Consistency:** Depending on whether the current login location matches historical patterns, the workflow branches to either the `New Location` or `Known Location` nodes. The `New Location` node triggers when a login from a new city is detected, indicating a potential security risk. Conversely, the `Known Location` node is activated when the login location is consistent with historical data, suggesting a regular login pattern."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "3e091a54-2fdc-491c-a168-0fb4fb704fd8", "name": "Sticky Note9", "type": "n8n-nodes-base.stickyNote", "position": [2310.5877845770297, 691.4637444823477], "parameters": {"width": 629.1148167417672, "height": 841.097003209987, "content": "![gmail]({{ $env.WEBHOOK_URL }}\n## \ud83d\udce7 Notifying Users About Unusual Login Attempts\n\nIn the final section of the \"Suspicious Login Detection\" workflow, the nodes `User has email?`, `HTML`, and `Inform user` work together to notify users about unusual login attempts, enhancing the security and responsiveness of the system.\n\n-   **Verifying Email Availability:** After fetching user details with `Query user by ID`, the `User has email?` node checks if the user has an email address on record. This verification is crucial to ensure that the notification process proceeds only for users with valid email addresses.\n\n-   **Crafting the Notification Message:** The `HTML` node is responsible for creating the email content. It generates a well-formatted HTML message informing the user of a recent login from a new device or location. The message includes details like username, timestamp, location, and device information, providing the user with specific insights into the login activity.\n\n-   **Sending the Email Alert:** Finally, the `Inform user` node sends out the email notification. This node uses Gmail to dispatch the message crafted by the `HTML` node to the user's email address obtained in the previous steps.\n\n-   **Enhancing User Awareness and Security:** By notifying users of unusual login activities, the workflow not only enhances security but also empowers users to take immediate action if the login was not authorized. This could include steps like changing their password or contacting the security team."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "f9c6f726-ce2f-448b-a392-b86e0507ce13", "name": "Sticky Note10", "type": "n8n-nodes-base.stickyNote", "position": [1858, 691.3527917931716], "parameters": {"width": 442.82773054232473, "height": 839.4355618292594, "content": "![postgre]({{ $env.WEBHOOK_URL }}\n## \ud83e\udde9 Querying User Details for Enhanced Context\n\nThe `Query user by ID` node plays a key role in gathering additional user-specific information to provide enhanced context for the security analysis.\n\n-   **User Information Retrieval:** The `Query user by ID` node interacts with a Postgres database to fetch detailed information about the user whose ID is associated with the current login attempt. This information is crucial for understanding the user's profile and access patterns.\n\n-   **Integrating with Location and Device Analysis:** This node is triggered following alerts from either the `New Location` or `New Device/Browser` nodes. These alerts indicate that the current login attempt is potentially suspicious due to a new location or device/browser being used.\n\n-   **Enriching Security Insight:** By querying detailed user data, the workflow gains a deeper understanding of the user's normal access patterns and profiles. This information can be instrumental in differentiating between legitimate user behavior and potential unauthorized access."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "6fd1a35c-5abc-4655-b5b5-836b49129d24", "name": "riot?", "type": "n8n-nodes-base.if", "position": [520, 380], "parameters": {"conditions": {"boolean": [{"value1": "={{ $('GreyNoise').item.json.riot }}", "value2": true}]}}, "typeVersion": 1, "notes": "This if node performs automated tasks as part of the workflow."}, {"id": "123fa821-4eb0-42b9-99c9-a0157f7ffac8", "name": "\ud83d\udd34 Priority: HIGH", "type": "n8n-nodes-base.set", "position": [1180, 220], "parameters": {"values": {"string": [{"name": "priority", "value": "\ud83d\udd34 High"}]}, "options": {}, "keepOnlySet": true}, "typeVersion": 2, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "459d0152-8184-4031-8f70-6c100f2bc6c3", "name": "\ud83d\udfe1 Priority: MEDIUM", "type": "n8n-nodes-base.set", "position": [1180, 360], "parameters": {"values": {"string": [{"name": "priority", "value": "\ud83d\udfe1 Medium"}]}, "options": {}}, "typeVersion": 2, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "58427db9-8ef7-4916-8564-727bd587401d", "name": "\ud83d\udfe2 Priority: LOW", "type": "n8n-nodes-base.set", "position": [1180, 500], "parameters": {"values": {"string": [{"name": "priority", "value": "\ud83d\udfe2 Low"}]}, "options": {}}, "typeVersion": 2, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "fd1e93a2-267e-4d5e-9724-6a4bb46b94b2", "name": "GreyNoise", "type": "n8n-nodes-base.httpRequest", "position": [280, 440], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {"response": {"response": {"neverError": true}}}, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpHeaderAuth"}, "credentials": {"httpHeaderAuth": {"id": "wwwfQfxzoBK7NH2a", "name": "n8n greynoise api key"}}, "typeVersion": 4.1, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "032b9558-a19b-4790-8593-8949ab2606d4", "name": "IP API", "type": "n8n-nodes-base.httpRequest", "position": [40, 1280], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {}}, "typeVersion": 4.1, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "6cff0db9-27c3-4c4b-9af0-e8a8d55ad107", "name": "UserParser", "type": "n8n-nodes-base.httpRequest", "position": [80, 1522], "parameters": {"url": "{{ $env.API_BASE_URL }}", "options": {}, "sendQuery": true, "authentication": "{{ $credentials.genericCredentialType }}", "genericAuthType": "httpQueryAuth", "queryParameters": {"parameters": [{"name": "ua", "value": "={{ $json.userAgent }}"}]}}, "credentials": {"httpQueryAuth": {"id": "33f1NrH1bLdXCGyw", "name": "n8n Userparser API Key"}}, "typeVersion": 4.1, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "65c7a039-5257-495d-86c2-18a44627ebe1", "name": "When clicking \"Execute Workflow\"", "type": "n8n-nodes-base.manualTrigger", "position": [-740, 880], "parameters": {}, "typeVersion": 1, "notes": "This manualTrigger node performs automated tasks as part of the workflow."}, {"id": "a038a10a-baaf-4649-9d38-4fa661dfc4ce", "name": "Example event", "type": "n8n-nodes-base.code", "position": [-480, 880], "parameters": {"jsCode": "return {\n  json:\n  {\n    \"headers\": {\n      \"host\": \"internal.users.n8n.cloud\",\n      \"user-agent\": \"PostmanRuntime/7.32.3\",\n      \"content-length\": \"857\",\n      \"accept\": \"*/*\",\n      \"accept-encoding\": \"gzip, deflate, br\",\n      \"content-type\": \"application/json\",\n      \"postman-token\": \"e10e747f-0668-4238-9a3d-148b2c8591da\",\n      \"x-forwarded-for\": \"10.255.0.2\",\n      \"x-forwarded-host\": \"internal.users.n8n.cloud\",\n      \"x-forwarded-port\": \"443\",\n      \"x-forwarded-proto\": \"https\",\n      \"x-forwarded-server\": \"e591fa1c2d01\",\n      \"x-real-ip\": \"10.255.0.2\"\n    },\n    \"params\": {},\n    \"query\": {},\n    \"body\": {\n      \"anonymousId\": \"b4191c58-7d64-4c93-8bb4-479c3c95d283\",\n      \"context\": {\n        \"ip\": \"2.204.248.108\",\n        \"library\": {\n          \"name\": \"analytics.js\",\n          \"version\": \"next-1.53.0\"\n        },\n        \"locale\": \"en-US\",\n        \"page\": {\n          \"path\": \"/login\",\n          \"referrer\": \"{{ $env.WEBHOOK_URL }}\",\n          \"search\": \"\",\n          \"title\": \"n8n.cloud\",\n          \"url\": \"{{ $env.WEBHOOK_URL }}\"\n        },\n        \"userAgent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/114.0\"\n      },\n      \"event\": \"User signed in\",\n      \"integrations\": {},\n      \"messageId\": \"ajs-next-a14f5b6e9860c7318a27f1ac05b3182d\",\n      \"originalTimestamp\": \"2023-06-28T11:26:46.302Z\",\n      \"properties\": {},\n      \"receivedAt\": \"2023-06-28T11:26:46.550Z\",\n      \"sentAt\": \"2023-06-28T11:26:46.313Z\",\n      \"timestamp\": \"2023-06-28T11:26:46.539Z\",\n      \"type\": \"track\",\n      \"userId\": \"staging-2055\"\n    }\n  }\n}"}, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow."}, {"id": "700a08d8-09ce-486c-bcfb-07d15f268d08", "name": "Sticky Note7", "type": "n8n-nodes-base.stickyNote", "position": [-803, -83], "parameters": {"width": 794.5711626683587, "height": 1175.5321499586535, "content": "![webhook]({{ $env.WEBHOOK_URL }}\n## Workflow Overview\n\nExperience enhanced cybersecurity with the `Suspicious Login Detection` workflow in n8n, your go-to solution for real-time monitoring and rapid response to suspicious login activities. This workflow is versatile, with both manual and automated webhook triggers to suit your testing and operational needs.\n\nThis [this GreyNoise guide]({{ $env.WEBHOOK_URL }} was used to design the architecture of this workflow and can serve as a guide for making your own version of this workflow.\n\nKey features include:\n\n- Data Extraction: Seamlessly extracts crucial data like IP addresses and user IDs from login events.\n- Triple-Threat Analysis: Splits into three paths for thorough scrutiny, using `GreyNoise` for IP trust assessment, `IP-API` for geolocation insights, and `UserParser` for user agent details.\n- Prioritized Alerts: Assigns alert priorities and swiftly notifies via `Slack`, ensuring immediate attention to high-risk activities.\n- In-depth Investigation: Cross-references login history for anomalies and flags potential threats, keeping your security team a step ahead.\n\n\nEasy to set up and adaptable, this n8n workflow is a powerhouse tool for safeguarding your digital environment. \n\n## \u25b6\ufe0fInitial Trigger: Detecting Suspicious Logins\n\nThe initial trigger of this workflow is the detection of new login events. This is achieved through a combination of a webhook (`New /login event` node), set to trigger upon a new /login event, and a manual trigger (`When clicking \"Execute Workflow\"` node) for testing purposes. The webhook is configured to receive data from login events, capturing vital information such as IP addresses and user details.\n\nThis setup is crucial for real-time monitoring of login activities. As soon as a login event occurs, the workflow springs into action, extracting and processing the relevant data using the `Extract relevant data` node. "}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "ff6bbb3c-1c14-4e94-bfae-58e8cbb098c4", "name": "Sticky Note11", "type": "n8n-nodes-base.stickyNote", "position": [0.113308604309168, 690], "parameters": {"width": 469.4801859287644, "height": 736.6018800373852, "content": "![ipapi]({{ $env.WEBHOOK_URL }}\n## \ud83c\udf10 IP Geolocation with IP-API\nThe `IP API` node in the \"Suspicious Login Detection\" workflow adds crucial geolocation context to login events. It queries IP-API for geographical data on the IP address extracted earlier.\n\n-   **Geographical Insight:** This node provides geographical details like country, region, and city, helping to identify unusual login locations that might signal a security risk.\n-   **Enhanced Security Analysis:** The geographical data aids in assessing the legitimacy of login attempts, adding a valuable layer to the security analysis.\n\n### Authentication - Free Tier Available (45 requests/min)\nThis endpoint is limited to `45 requests per minute from an IP address`.\n\nIf you go over the limit your requests will be throttled `(HTTP 429)` until your rate limit window is reset. If you constantly go over the limit your IP address will be banned for 1 hour.\n\nNo authentication needed, [Click here to view documentation.]({{ $env.API_BASE_URL }}"}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "57adbcf5-f927-4bdb-b863-bcff97be0ace", "name": "Sticky Note12", "type": "n8n-nodes-base.stickyNote", "position": [0, 1435], "parameters": {"width": 470.4372486447854, "height": 1044.866146557656, "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n![userparser]({{ $env.WEBHOOK_URL }}\n## \ud83d\udd04 Merging Geolocation and User Agent Data\n\nIn the \"Suspicious Login Detection\" workflow, the `Merge` node plays a pivotal role in synthesizing information from the `IP API` and `UserParser` nodes.\n\n-   **Data Integration:** The `Merge` node combines data from two key sources: geolocation details from the `IP API` node and user agent information from the `UserParser` node. This integration offers a comprehensive view of each login event.\n\n-   **Comprehensive Analysis:** By merging geolocation and user agent data, the workflow gains a fuller understanding of the context behind each login attempt, crucial for accurately assessing security risks.\n\n-   **Efficient Workflow Design:** The use of the `Merge` node demonstrates n8n's efficient handling of diverse data streams, ensuring that all relevant information is brought together for a cohesive analysis.\n\n\n### Authentication - Free Tier Available (10000 calls / month)\nThis endpoint is limited to `500 calls / day`.\n\nTo set your API key for UserParser, open the `UserParser HTTP Request` node, and add a new authentication credential. Choose `Generic Credential Type` then `Query Auth`. Lastly, under `Credential for Query Auth` set the name to `api_key` and value to your `api key`.\n\n[Click here to view documentation.]({{ $env.API_BASE_URL }}"}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "44830be0-428a-492e-97f7-66289fac6231", "name": "Sticky Note13", "type": "n8n-nodes-base.stickyNote", "position": [1184, 1590], "parameters": {"width": 659.8254746666762, "height": 845.1421530016269, "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n![userparser]({{ $env.WEBHOOK_URL }}\n## \ud83d\udcf1 Identifying Device and Browser Anomalies\nthe `Parse User Agent` and `New Device/Browser?` nodes focus on detecting anomalies in device and browser usage for login events.\n\n-   **Parsing User Agent Data:** The `Parse User Agent` node uses the UserParser API to analyze the user agent string from the current login attempt. This node extracts detailed information about the browser, operating system, and device type used for the login, offering crucial insights into the login environment.\n\n-   **Comparing with Historical Data:** After parsing the user agent data, the workflow proceeds to the `New Device/Browser?` node. This node compares the current login's device and browser details against the user's historical data (retrieved by the `Get last 10 logins from the same user` node) to check for any discrepancies.\n\n-   **Detecting New Device or Browser Use:** The `New Device/Browser?` node checks if there's a change in the browser name, operating system, or device type. A change might indicate that the current login is being attempted from a new device or browser, which could be a sign of unauthorized access.\n\n-   **Routing Based on Device and Browser Consistency:** The workflow bifurcates based on this analysis. If a new device or browser is detected, the flow moves to the `New Device/Browser` node, suggesting potential security risks. Conversely, if the device and browser match historical patterns, the `Old Device/Browser` node is activated, indicating a routine login."}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "e0bcc621-ff1f-47ca-a63a-f1af5c521c9a", "name": "Known, Do Nothing", "type": "n8n-nodes-base.noOp", "position": [960, 1440], "parameters": {}, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}, {"id": "92c08a63-6961-40f6-993e-052a311f4bb6", "name": "Known Location", "type": "n8n-nodes-base.noOp", "position": [1660, 1420], "parameters": {}, "executeOnce": true, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}, {"id": "bb1621e0-8297-4e6c-bcdf-eae683a4b830", "name": "Old Device/Browser", "type": "n8n-nodes-base.noOp", "position": [1674, 1765], "parameters": {}, "executeOnce": true, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}, {"id": "9c987dd1-8d27-4067-9956-712eae4a228c", "name": "Not Riot", "type": "n8n-nodes-base.noOp", "position": [780, 520], "parameters": {}, "typeVersion": 1, "notes": "This noOp node performs automated tasks as part of the workflow."}], "active": false, "pinData": {}, "settings": {"executionOrder": "v1", "saveManualExecutions": true, "callerPolicy": "workflowsFromSameOwner", "errorWorkflow": null, "timezone": "UTC", "executionTimeout": 3600, "maxExecutions": 1000, "retryOnFail": true, "retryCount": 3, "retryDelay": 1000}, "versionId": "cd2fd77a-2903-44b8-826a-6797efb5f871", "connections": {"d7dea680-14f3-4ffd-bfaf-f928b69d801d": {"main": [[{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-1875515a", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-a265528d", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-141d719e", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-785f029d", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-7793f9a0", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-5c4ec335", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-bbaa24fb", "type": "main", "index": 0}], [{"node": "error-handler-d7dea680-14f3-4ffd-bfaf-f928b69d801d-b8d7baaa", "type": "main", "index": 0}]]}, "90e859b2-aa64-48e7-a8fe-696e3b7216f1": {"main": [[{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-9ec2cdf6", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-c6b94861", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-1ac5e611", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-788f3a19", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-8e0a0aca", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-29764c45", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-3d3dbbed", "type": "main", "index": 0}], [{"node": "error-handler-90e859b2-aa64-48e7-a8fe-696e3b7216f1-6e4e5f20", "type": "main", "index": 0}]]}, "fb4d5d07-58ae-4b17-a389-29e7fbe2caa2": {"main": [[{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-03f11a18", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-f2ae4cbe", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-c8907de3", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-67439784", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-addbc405", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-0e786322", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-f6bc28e4", "type": "main", "index": 0}], [{"node": "error-handler-fb4d5d07-58ae-4b17-a389-29e7fbe2caa2-951dec10", "type": "main", "index": 0}]]}, "fd1e93a2-267e-4d5e-9724-6a4bb46b94b2": {"main": [[{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-e38184c2", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-912e7d0c", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-5b69e11e", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-032bb62d", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-c7565b3d", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-062f2a84", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-7b9f5101", "type": "main", "index": 0}], [{"node": "error-handler-fd1e93a2-267e-4d5e-9724-6a4bb46b94b2-6096ea2a", "type": "main", "index": 0}]]}, "032b9558-a19b-4790-8593-8949ab2606d4": {"main": [[{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-cff019dc", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-8aa6b378", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-0e61e5e6", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-476349b2", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-f5ea62f8", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-f9a01374", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-472ba571", "type": "main", "index": 0}], [{"node": "error-handler-032b9558-a19b-4790-8593-8949ab2606d4-437e2c56", "type": "main", "index": 0}]]}, "6cff0db9-27c3-4c4b-9af0-e8a8d55ad107": {"main": [[{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-2c7125eb", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-e5982839", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-9936a38c", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-3d0f906f", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-7bcc4c67", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-9192e0da", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-96dbc50e", "type": "main", "index": 0}], [{"node": "error-handler-6cff0db9-27c3-4c4b-9af0-e8a8d55ad107-eb44a01a", "type": "main", "index": 0}]]}, "5be949da-f04a-44f9-9cf0-5e221f9d27e8": {"main": [[{"node": "error-handler-5be949da-f04a-44f9-9cf0-5e221f9d27e8-74a00231", "type": "main", "index": 0}]]}}, "description": "Automated workflow: Suspicious_login_detection. This workflow integrates 15 different services: webhook, stickyNote, httpRequest, code, merge. It contains 56 nodes and follows best practices for error handling and security.", "notes": "Excellent quality workflow: Suspicious_login_detection. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."}