{
  "name": "TOTP VALIDATION (WITHOUT CREATING CREDENTIAL)",
  "nodes": [
    {
      "id": "56f102c4-5b84-4e30-955c-0ea1221c328f",
      "name": "When clicking ‘Test workflow’",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        480,
        680
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "4f562819-ee42-42ad-b821-aff2cbebbc0f",
      "name": "TOTP VALIDATION",
      "type": "n8n-nodes-base.code",
      "position": [
        920,
        680
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import hmac\nimport hashlib\nimport time\nimport base64\n\ndef base32_decode(key):\n    \"\"\"Decodes a base32 key into bytes\"\"\"\n    key += '=' * (-len(key) % 8)  # Add necessary '=' for valid length\n    return base64.b32decode(key.upper(), casefold=True)\n\ndef generate_totp(secret, interval=30, digits=6):\n    \"\"\"Generates a TOTP code based on a secret key\"\"\"\n    interval_count = int(time.time() // interval)\n    interval_bytes = interval_count.to_bytes(8, byteorder='big')\n\n    hmac_hash = hmac.new(secret, interval_bytes, hashlib.sha1).digest()\n    \n    offset = hmac_hash[-1] & 0x0F\n    binary_code = ((hmac_hash[offset] & 0x7F) << 24 |\n                   (hmac_hash[offset + 1] & 0xFF) << 16 |\n                   (hmac_hash[offset + 2] & 0xFF) << 8 |\n                   (hmac_hash[offset + 3] & 0xFF))\n    \n    otp_code = binary_code % (10 ** digits)\n    \n    # Format with leading zeros if necessary\n    otp_code_str = str(otp_code).zfill(digits)\n    \n    return otp_code_str\n\ndef verify_totp(secret, code, interval=30, digits=6):\n    \"\"\"Checks whether the TOTP code is valid\"\"\"\n    secret_bytes = base32_decode(secret)\n    generated_code = generate_totp(secret_bytes, interval, digits)\n    \n    return generated_code == code\n\n# Example of use\nsecret = _input.item.json.totp_secret_example  # Secret key base32 (example)\ncode =  _input.item.json.code_to_verify_example # Code to check (example)\n\n# Return 1 if code is valid. Return 0 if invalid\nif verify_totp(secret, code):\n    return [{\"status\": 1}]\nelse:\n    return [{\"status\": 0}]"
      },
      "typeVersion": 2
    },
    {
      "id": "9760b31c-5ba8-4001-9cbe-2be2ae58d58e",
      "name": "IF CODE IS VALID",
      "type": "n8n-nodes-base.if",
      "position": [
        1140,
        680
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "470cf368-daee-4136-b907-a3539765871d",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": 1
            }
          ]
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "3a029863-8fd0-42ef-b8ff-9f7cdf6e8d94",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        440,
        180
      ],
      "parameters": {
        "width": 883,
        "height": 430,
        "content": "## TOTP Validation with Function Node\n\nThis template allows you to verify if a 6-digit TOTP code is valid using the corresponding TOTP secret. It can be used in an authentication system.\n### Example usage:\n- You retrieve the user's TOTP secret from a database, then you want to verify if the 2FA code provided by the user is valid.\n\n## Setup Guidelines\n\nYou only need the \"TOTP VALIDATION\" node.\nYou will need to modify lines 39 and 40 of the \"TOTP VALIDATION\" node with the correct values for your specific context.\n\n## Testing the Template\nYou can define a sample secret and code in the \"EXAMPLE FIELDS\" node below, then click \"Test Workflow\".\nIf the code is valid for the provided secret, the flow will proceed to the \"true\" branch of the \"IF CODE IS VALID\" node. Otherwise, it will go to the \"false\" branch."
      },
      "typeVersion": 1
    },
    {
      "id": "f660a50f-2c33-49bb-b975-8d51e9bf24ed",
      "name": "EXAMPLE FIELDS",
      "type": "n8n-nodes-base.set",
      "position": [
        700,
        680
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "03a66bf9-1bf4-44c0-92e0-edd45929e467",
              "name": "code_to_verify_example",
              "type": "string",
              "value": "516620"
            },
            {
              "id": "7bb18b0a-1851-4f27-a91f-5f93b663cfd0",
              "name": "totp_secret_example",
              "type": "string",
              "value": "CNSUKUMZLQJEZJ3"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "EXAMPLE FIELDS": {
      "main": [
        [
          {
            "node": "TOTP VALIDATION",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TOTP VALIDATION": {
      "main": [
        [
          {
            "node": "IF CODE IS VALID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Test workflow’": {
      "main": [
        [
          {
            "node": "EXAMPLE FIELDS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}