{
  "name": "Host your own JWT authentication system with Data Tables and token management",
  "nodes": [
    {
      "id": "d4d5e7a8-c447-4239-a570-2c705868974d",
      "name": "Generate Salt",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -848,
        -1248
      ]
    },
    {
      "id": "8c643b0d-574b-4c8a-a00a-f8587dfed883",
      "name": "Hash Password",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -576,
        -1248
      ]
    },
    {
      "id": "01a0c5fa-d902-4ee3-9116-240a1bc54d71",
      "name": "Process login webhook",
      "type": "n8n-nodes-base.set",
      "position": [
        560,
        -1280
      ]
    },
    {
      "id": "cd32f96d-a552-4522-86c6-c35010193be0",
      "name": "Get User",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        992,
        -1200
      ]
    },
    {
      "id": "c91e3b78-b71a-4fde-92c6-41cc99e75c0c",
      "name": "Extract Salt & Hash",
      "type": "n8n-nodes-base.code",
      "position": [
        1360,
        -1200
      ]
    },
    {
      "id": "03a90300-9b8c-43cd-b51d-fcdc4a2abc85",
      "name": "Hash Input Password",
      "type": "n8n-nodes-base.crypto",
      "position": [
        1536,
        -1200
      ]
    },
    {
      "id": "b70a3266-04fc-4398-ac19-7fb2cbf005f7",
      "name": "Sign Access Token",
      "type": "n8n-nodes-base.crypto",
      "position": [
        2176,
        -1328
      ]
    },
    {
      "id": "a17a5545-1961-48e5-8e5a-4cc51f16d32f",
      "name": "Sign Refresh Token",
      "type": "n8n-nodes-base.crypto",
      "position": [
        2176,
        -1104
      ]
    },
    {
      "id": "9c400b40-273f-43ac-b6db-81ef5dd410cb",
      "name": "Format JWT Tokens",
      "type": "n8n-nodes-base.code",
      "position": [
        2560,
        -1216
      ]
    },
    {
      "id": "638d49ae-5b15-49a8-b7f0-e5c32308e0e6",
      "name": "Merge JWT Tokens",
      "type": "n8n-nodes-base.merge",
      "position": [
        2400,
        -1216
      ]
    },
    {
      "id": "a1f01174-648e-45cc-9bd0-cb4294f8dccc",
      "name": "Hash Refresh Token for Storage",
      "type": "n8n-nodes-base.crypto",
      "position": [
        2752,
        -1216
      ]
    },
    {
      "id": "ca71f487-e4c7-4f33-a6f8-b7a13a3f90b5",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -1360
      ],
      "parameters": {
        "width": 3344,
        "height": 608,
        "content": "## Login Flow"
      }
    },
    {
      "id": "4f8558f6-0a62-49e4-a04d-85cba870e6ab",
      "name": "Parse JWT",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        160
      ]
    },
    {
      "id": "3ed751a2-bf2d-4e65-a13e-487b117f8e01",
      "name": "Verify HMAC Signature",
      "type": "n8n-nodes-base.crypto",
      "position": [
        1280,
        160
      ]
    },
    {
      "id": "e503f741-5c7e-4bf2-bc0f-14a9484c6a80",
      "name": "Compare Signatures",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        160
      ]
    },
    {
      "id": "76d82b8d-a879-41cc-8358-af930333ad19",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -16
      ],
      "parameters": {
        "width": 1616,
        "height": 496,
        "content": "## Verify Token Flow"
      }
    },
    {
      "id": "5761b1d1-22fd-43c8-85a7-ae967630c44a",
      "name": "Create User",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -304,
        -1248
      ]
    },
    {
      "id": "469e109c-a981-49be-bbe7-b24bd0467f04",
      "name": "Registration Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2240,
        -1232
      ]
    },
    {
      "id": "82ca8cb5-4eda-45ee-96bf-dfa520a44726",
      "name": "Format Password & Salt",
      "type": "n8n-nodes-base.code",
      "position": [
        -848,
        -960
      ]
    },
    {
      "id": "07149331-060d-4d01-a418-4f1a2abe4813",
      "name": "Format User Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -592,
        -944
      ]
    },
    {
      "id": "b460d06f-759c-47ca-9cc4-b33e49489563",
      "name": "Error Registration Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -64,
        -1024
      ]
    },
    {
      "id": "c0751a62-a1af-441a-a8db-583eddabd3f3",
      "name": "Validate Registration Request",
      "type": "n8n-nodes-base.code",
      "position": [
        -1968,
        -1232
      ]
    },
    {
      "id": "1ecf5f63-5099-4aaa-ab89-de65c7e6dbcd",
      "name": "Registration Successful",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -64,
        -1264
      ]
    },
    {
      "id": "5439ebb6-4ec7-4fe5-be49-f44b0c45d889",
      "name": "If User Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        1152,
        -1216
      ]
    },
    {
      "id": "083ce4f7-f48a-4d28-8265-4aa75b87d642",
      "name": "User Not Found",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1136,
        -960
      ]
    },
    {
      "id": "53f40d35-f65e-4a17-9041-910a31b3d652",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        2928,
        -1216
      ]
    },
    {
      "id": "04d49b68-8955-498e-a60f-4ed4e89e55ef",
      "name": "Update User Refresh Token",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        3136,
        -1344
      ]
    },
    {
      "id": "c91111d8-9657-44c0-be37-07bce3b60fd6",
      "name": "Store Refresh Token",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        3136,
        -1104
      ]
    },
    {
      "id": "032cfc35-65e3-4b0c-a326-d4ea61228cc5",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        3344,
        -1216
      ]
    },
    {
      "id": "9112cefa-951d-4e30-9148-6f83625f78fd",
      "name": "Verify Access Token",
      "type": "n8n-nodes-base.webhook",
      "position": [
        416,
        32
      ]
    },
    {
      "id": "38b357fd-91a3-4e3a-82de-62b71a556fbb",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        448,
        320
      ]
    },
    {
      "id": "8cc94ddc-6bbd-44a7-b7f0-afbad69d7daf",
      "name": "Refresh Access Token",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -2336,
        -16
      ]
    },
    {
      "id": "f9946939-4efe-43e4-8626-69ddb41b618a",
      "name": "Parse Refresh Token",
      "type": "n8n-nodes-base.code",
      "position": [
        -1904,
        0
      ]
    },
    {
      "id": "b0c044ef-13cc-4711-b7dd-3db0d176f202",
      "name": "Verify Signature",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -1904,
        272
      ]
    },
    {
      "id": "d426f5e3-dd5c-485e-bd8e-ef9c8b0a028d",
      "name": "Compare Refresh Token Signature",
      "type": "n8n-nodes-base.code",
      "position": [
        -1648,
        0
      ]
    },
    {
      "id": "597d6c4f-0b0e-4777-867c-6a883d128dcc",
      "name": "Hash Refresh Token For DB Lookup",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -1648,
        272
      ]
    },
    {
      "id": "56f2e5a6-460d-4a6c-ade3-f7e99d9ae99e",
      "name": "If Refresh Token Exists",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -1392,
        16
      ]
    },
    {
      "id": "98469d0f-cebc-4cf0-b775-1d72769d0560",
      "name": "If Refresh Token Is Valid",
      "type": "n8n-nodes-base.if",
      "position": [
        -1200,
        16
      ]
    },
    {
      "id": "8d1c5fee-ca4a-4e5d-8efd-b9196d1cf9d1",
      "name": "Create Access Token Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        -992,
        0
      ]
    },
    {
      "id": "860e8b13-759e-4c81-861e-44c8c8e3bd51",
      "name": "Format Access Token JWT",
      "type": "n8n-nodes-base.code",
      "position": [
        -624,
        0
      ]
    },
    {
      "id": "7ec78f50-e2bc-4f9e-a063-f5cee4e05562",
      "name": "Return New Access Token",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -448,
        0
      ]
    },
    {
      "id": "fa47661a-acb6-42b2-8783-b6c21fedf42b",
      "name": "Session Expired",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -992,
        272
      ]
    },
    {
      "id": "ffea7a05-b838-44cc-b9b5-2177cf31c97f",
      "name": "Parse Register Request",
      "type": "n8n-nodes-base.set",
      "position": [
        -2256,
        -976
      ]
    },
    {
      "id": "9edc4ba9-11b5-4705-8846-0623eec15b35",
      "name": "Login Successful",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3520,
        -1216
      ]
    },
    {
      "id": "74bb0bc8-75c7-444d-b396-a797598a95ef",
      "name": "Login Credentials Invalid Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1696,
        -976
      ]
    },
    {
      "id": "91534fa0-06f0-466b-a751-cd736e38e212",
      "name": "Process Verify Token Webhook",
      "type": "n8n-nodes-base.set",
      "position": [
        592,
        32
      ]
    },
    {
      "id": "ba27471d-e369-4ae3-af7d-11c6f6375dc6",
      "name": "Verify Input",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        -1184
      ]
    },
    {
      "id": "207cace5-a58b-4b4d-bf5b-5bc2516f8ae1",
      "name": "Verify Password",
      "type": "n8n-nodes-base.code",
      "position": [
        1696,
        -1200
      ]
    },
    {
      "id": "8307d145-aaec-459c-9709-f60c41bb355e",
      "name": "Create JWT Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        1904,
        -1216
      ]
    },
    {
      "id": "d55ad76d-58a1-405b-a916-10896e6aacef",
      "name": "Process Refresh Token",
      "type": "n8n-nodes-base.set",
      "position": [
        -2160,
        -16
      ]
    },
    {
      "id": "e1e60536-b002-44f6-af55-4382c343e4fd",
      "name": "Sign New Access Token",
      "type": "n8n-nodes-base.crypto",
      "position": [
        -816,
        0
      ]
    },
    {
      "id": "1c20777d-fbd2-45ab-846a-11664df3a0a3",
      "name": "If Username Is Available",
      "type": "n8n-nodes-base.if",
      "position": [
        -1568,
        -1264
      ]
    },
    {
      "id": "2057c030-5dc4-4adb-9c35-18cf15f3d282",
      "name": "Get User By Username",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -1760,
        -1248
      ]
    },
    {
      "id": "d2cb987b-183d-4ea7-be00-8b0181df6e89",
      "name": "Username Taken Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -1568,
        -960
      ]
    },
    {
      "id": "2dc548d9-838f-4f7b-9076-768d1ae0bbbe",
      "name": "Registration Request Invalid Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -1984,
        -960
      ]
    },
    {
      "id": "c5f15368-adbc-426a-afe7-c418ebdbc810",
      "name": "If Email Is Available",
      "type": "n8n-nodes-base.if",
      "position": [
        -1120,
        -1264
      ]
    },
    {
      "id": "da039f08-ad18-4783-9fae-ab35ddaeab93",
      "name": "Get User By Email",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        -1328,
        -1248
      ]
    },
    {
      "id": "551765c6-9690-4044-9767-81d280101024",
      "name": "Email Taken Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -1120,
        -960
      ]
    },
    {
      "id": "926df073-ee05-45a4-8221-1eeae39095ec",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2352,
        -1360
      ],
      "parameters": {
        "width": 2496,
        "height": 608,
        "content": "## Registration Flow"
      }
    },
    {
      "id": "beef3c9d-e920-4038-9003-6fa317457706",
      "name": "Login Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        400,
        -1280
      ]
    },
    {
      "id": "707614cc-c896-40ef-97c9-2a433182ad59",
      "name": "Bad Request",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        784,
        -960
      ]
    },
    {
      "id": "c0d24010-60fa-445b-881e-1bce33fd3e66",
      "name": "Access Token Valid",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1728,
        16
      ]
    },
    {
      "id": "3078f280-cdf6-47c9-b7e2-b06801ac0245",
      "name": "Access Token Invalid",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1744,
        272
      ]
    },
    {
      "id": "4607d4be-8a77-4b1b-9d74-1a435acbc98e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2368,
        -80
      ],
      "parameters": {
        "width": 2176,
        "height": 560,
        "content": "## Refresh Token Flow"
      }
    },
    {
      "id": "a8f6dfcf-9f47-4153-a472-da54b44d2a8b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2352,
        -1664
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "## 📝 REGISTRATION FLOW\n\nChecks username → Checks email → Creates user\n\nDuplicate Prevention:\n- Username must be unique\n- Email must be unique\n- Checks happen BEFORE password hashing (saves resources)\n"
      }
    },
    {
      "id": "175cc098-cf21-427c-885b-aa8c01056d10",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1888,
        -1664
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "## 🔐 PASSWORD SECURITY\n\n1. Random salt generated (unique per user)\n2. Password + Salt combined\n3. Hashed with SHA-512 (irreversible)\n4. Stored as \"salt:hash\"\n\nWhy salt? Makes every password hash uniqu"
      }
    },
    {
      "id": "ab2930d7-7130-4876-acb6-79956f83ed0c",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -1680
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "## 🔑 LOGIN FLOW\n\nValidates input → Finds user → Verifies password\n→ Generates tokens → Stores refresh token → Returns tokens\n\nPassword Verification:\n- Extracts salt from stored \"salt:hash\"\n- Hashes in"
      }
    },
    {
      "id": "cc909ef8-b87e-48d1-9f2e-d06b2704558f",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2000,
        -1776
      ],
      "parameters": {
        "width": 448,
        "height": 384,
        "content": "## 🎫 TWO TOKEN SYSTEM\n\nAccess Token (15 min):\n- For API requests\n- Short lifespan = more secure\n- Not stored in DB\n\nRefresh Token (7 days):\n- Gets new access tokens\n- Long lifespan = better UX\n- Store"
      }
    },
    {
      "id": "719b318f-746a-40f5-b3ec-b7ef4ddaad5b",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -320
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "✅ TOKEN VERIFICATION\n\n1. Parse token into parts\n2. Check expiration time\n3. Recreate signature with secret key\n4. Compare signatures\n\nIf signature doesn't match → Token was tampered with\nIf expired → "
      }
    },
    {
      "id": "85218220-90b2-481b-aef8-7fa9a5d6db31",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2368,
        -384
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "## 🔄 REFRESH PROCESS\n\nClient sends refresh token →\nVerify signature → Check expiration →\nLookup in database → Generate new access token\n\nDatabase Check:\nAllows token revocation (logout all devices)\nDe"
      }
    },
    {
      "id": "4f2b4bff-9e34-4a92-8427-766ae54fa997",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1904,
        -384
      ],
      "parameters": {
        "width": 432,
        "height": 272,
        "content": "## 🔒 DEFENSE IN DEPTH\n\nRefresh token is hashed (SHA-256) before storing.\n\nWhy? If database leaks:\n- Attacker can't use tokens directly\n- Must crack SHA-256 (very hard)\n- Adds security layer\n\nUser send"
      }
    },
    {
      "id": "564f1dd3-11c1-4e00-9139-6d81404b821c",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4224,
        -688
      ],
      "parameters": {
        "width": 416,
        "height": 336,
        "content": "## 🔑 CRITICAL SECURITY\n\nTwo secret keys used:\n- ACCESS_SECRET: Signs access tokens\n- REFRESH_SECRET: Signs refresh tokens\n\n⚠️ MUST be identical everywhere:\n- Login workflow (signing)\n- Verify workflow"
      }
    },
    {
      "id": "e9cf5472-0061-48e2-95e4-b65ed512fd3c",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3744,
        -688
      ],
      "parameters": {
        "width": 416,
        "height": 336,
        "content": "## ⚠️ TROUBLESHOOTING\n\n\"Invalid signature\":\n→ Check secret keys match everywhere\n\n\"Token not found in DB\":\n→ Check hash type (SHA256 + HEX encoding)\n\n\"Cannot read property\":\n→ Check node references $("
      }
    },
    {
      "id": "2382a6af-4e25-4495-be93-22f9cb945203",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3152,
        -1520
      ],
      "parameters": {
        "width": 416,
        "height": 336,
        "content": "## 🧪 TEST SEQUENCE\n\n1. Register new user\n2. Login with credentials\n3. Copy accessToken and refreshToken\n4. Verify access token\n5. Wait 15+ min OR manually test refresh\n6. Use refresh token to get new "
      }
    },
    {
      "id": "0d27d432-abbe-42b1-9a9a-b70434e4aa38",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3616,
        -1520
      ],
      "parameters": {
        "width": 416,
        "height": 576,
        "content": "# 💾 TABLE SETUP\n\n## **Use n8n Data Tables Feature**\n\n### Table 'users':\n- **email** string (login identifier)\n- **username** string (login identifier)\n- **password_hash** string (as \"salt:hash\")\n- **r"
      }
    },
    {
      "id": "4cc02f8c-a459-40a1-981d-247e9e311e14",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2496,
        -1776
      ],
      "parameters": {
        "width": 384,
        "height": 384,
        "content": "⚙️ CUSTOMIZATION POINTS\n\nChange token lifespan:\n- Find: exp: now + (15 * 60)\n- Adjust: (30 * 60) = 30 minutes\n\nChange hash algorithm:\n- Update Crypto nodes (SHA256 → SHA512)\n- Must update ALL instance"
      }
    },
    {
      "id": "71e19da5-0fdb-466e-bea1-42dead1f983e",
      "name": "SET ACCESS AND REFRESH SECRET",
      "type": "n8n-nodes-base.set",
      "position": [
        496,
        -976
      ]
    },
    {
      "id": "f5267c80-05c8-4378-aad1-c8ff115d1d82",
      "name": "Sticky Note32",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        432,
        -1024
      ],
      "parameters": {
        "width": null,
        "height": 256,
        "content": ""
      }
    },
    {
      "id": "2d74c194-e5a8-489e-a90b-f21e2740e173",
      "name": "Sticky Note33",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        368,
        -736
      ],
      "parameters": {
        "width": 416,
        "height": 192,
        "content": "## !! ATTENTION !!\nYou can use this node to set the **ACCESS_SECRET** and **REFRESH_SECRET**, but ideally you will use Variables to do this:\n\nYou will need to handle authenticating requests in differe"
      }
    },
    {
      "id": "682c87b6-9388-43bf-8981-c2d07fcb1996",
      "name": "Sticky Note34",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        816,
        -736
      ],
      "parameters": {
        "width": 448,
        "height": 240,
        "content": "## Migrating to Variables\n### You'll need to change following nodes to use Variables instead of Set Node:\n- **'Sign Access Token'** and **'Sign Refresh Token'** nodes to use the Variables\n- **Verify S"
      }
    },
    {
      "id": "85544cc1-ee32-45e7-9257-17a7a1e3924b",
      "name": "Sticky Note35",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4224,
        -1520
      ],
      "parameters": {
        "width": 560,
        "height": 640,
        "content": "# 🔐 COMPLETE AUTH WORKFLOW OVERVIEW\n\nImplement a complete auth process using n8n workflow. This template will enable you to easily add authentication to any application you need. Real production apps "
      }
    },
    {
      "id": "0c46dac3-dad7-4aa9-ba02-ca1f3f59e4e2",
      "name": "Sticky Note37",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4240,
        -1664
      ],
      "parameters": {
        "width": 1616,
        "height": 80,
        "content": "# Workflow Overview And Setup"
      }
    },
    {
      "id": "d5b86a70-6837-4664-acfd-62538f6c7066",
      "name": "Sticky Note38",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4256,
        -816
      ],
      "parameters": {
        "width": 1616,
        "height": 80,
        "content": "# Important Notes"
      }
    },
    {
      "id": "9064bdba-5fcf-43d0-a3e9-3d7eab89b319",
      "name": "SET ACCESS AND REFRESH SECRET1",
      "type": "n8n-nodes-base.set",
      "position": [
        -2240,
        272
      ]
    },
    {
      "id": "363e999b-554f-4396-b33a-846889a8cd4c",
      "name": "Sticky Note36",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2320,
        208
      ],
      "parameters": {
        "width": null,
        "height": 256,
        "content": ""
      }
    },
    {
      "id": "4f228c6f-9a05-4085-9c17-d980b2b0f3e5",
      "name": "SET ACCESS AND REFRESH SECRET2",
      "type": "n8n-nodes-base.set",
      "position": [
        1072,
        160
      ]
    },
    {
      "id": "5232ecb8-1844-4352-80cc-eff4d17856eb",
      "name": "Sticky Note39",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        112
      ],
      "parameters": {
        "width": null,
        "height": 256,
        "content": ""
      }
    }
  ],
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Login Successful",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get User": {
      "main": [
        [
          {
            "node": "If User Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse JWT": {
      "main": [
        [
          {
            "node": "SET ACCESS AND REFRESH SECRET2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create User": {
      "main": [
        [
          {
            "node": "Registration Successful",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Registration Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Input": {
      "main": [
        [
          {
            "node": "Get User",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Bad Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Salt": {
      "main": [
        [
          {
            "node": "Format Password & Salt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash Password": {
      "main": [
        [
          {
            "node": "Format User Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Login Webhook": {
      "main": [
        [
          {
            "node": "Process login webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If User Exists": {
      "main": [
        [
          {
            "node": "Extract Salt & Hash",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "User Not Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Password": {
      "main": [
        [
          {
            "node": "Create JWT Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Login Credentials Invalid Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format User Data": {
      "main": [
        [
          {
            "node": "Create User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge JWT Tokens": {
      "main": [
        [
          {
            "node": "Format JWT Tokens",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Signature": {
      "main": [
        [
          {
            "node": "Compare Refresh Token Signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format JWT Tokens": {
      "main": [
        [
          {
            "node": "Hash Refresh Token for Storage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get User By Email": {
      "main": [
        [
          {
            "node": "If Email Is Available",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sign Access Token": {
      "main": [
        [
          {
            "node": "Merge JWT Tokens",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Update User Refresh Token",
            "type": "main",
            "index": 0
          },
          {
            "node": "Store Refresh Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Signatures": {
      "main": [
        [
          {
            "node": "Access Token Valid",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Access Token Invalid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create JWT Payload": {
      "main": [
        [
          {
            "node": "Sign Access Token",
            "type": "main",
            "index": 0
          },
          {
            "node": "Sign Refresh Token",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Sign Refresh Token": {
      "main": [
        [
          {
            "node": "Merge JWT Tokens",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Extract Salt & Hash": {
      "main": [
        [
          {
            "node": "Hash Input Password",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash Input Password": {
      "main": [
        [
          {
            "node": "Verify Password",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Refresh Token": {
      "main": [
        [
          {
            "node": "Verify Signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Refresh Token": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Verify Access Token": {
      "main": [
        [
          {
            "node": "Process Verify Token Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get User By Username": {
      "main": [
        [
          {
            "node": "If Username Is Available",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Refresh Access Token": {
      "main": [
        [
          {
            "node": "Process Refresh Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registration Webhook": {
      "main": [
        [
          {
            "node": "Parse Register Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Email Is Available": {
      "main": [
        [
          {
            "node": "Generate Salt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Taken Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Refresh Token": {
      "main": [
        [
          {
            "node": "SET ACCESS AND REFRESH SECRET1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process login webhook": {
      "main": [
        [
          {
            "node": "SET ACCESS AND REFRESH SECRET",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sign New Access Token": {
      "main": [
        [
          {
            "node": "Format Access Token JWT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify HMAC Signature": {
      "main": [
        [
          {
            "node": "Compare Signatures",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Password & Salt": {
      "main": [
        [
          {
            "node": "Hash Password",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Register Request": {
      "main": [
        [
          {
            "node": "Validate Registration Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Access Token JWT": {
      "main": [
        [
          {
            "node": "Return New Access Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Refresh Token Exists": {
      "main": [
        [
          {
            "node": "If Refresh Token Is Valid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Username Is Available": {
      "main": [
        [
          {
            "node": "Get User By Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Username Taken Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Refresh Token Is Valid": {
      "main": [
        [
          {
            "node": "Create Access Token Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Session Expired",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update User Refresh Token": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Access Token Payload": {
      "main": [
        [
          {
            "node": "Sign New Access Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Verify Token Webhook": {
      "main": [
        [
          {
            "node": "Parse JWT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SET ACCESS AND REFRESH SECRET": {
      "main": [
        [
          {
            "node": "Verify Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Registration Request": {
      "main": [
        [
          {
            "node": "Get User By Username",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Registration Request Invalid Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash Refresh Token for Storage": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SET ACCESS AND REFRESH SECRET1": {
      "main": [
        [
          {
            "node": "Parse Refresh Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SET ACCESS AND REFRESH SECRET2": {
      "main": [
        [
          {
            "node": "Verify HMAC Signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Refresh Token Signature": {
      "main": [
        [
          {
            "node": "Hash Refresh Token For DB Lookup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash Refresh Token For DB Lookup": {
      "main": [
        [
          {
            "node": "If Refresh Token Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Parse JWT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}