AutomationFlowsData & Sheets › Check Jwt Security of API Endpoints with Http Requests and Google Sheets

Check Jwt Security of API Endpoints with Http Requests and Google Sheets

ByArminas B @abeka on n8n.io

This workflow reads API endpoints and JWTs from Google Sheets, tests each endpoint with multiple token scenarios using HTTP requests, and writes a risk-scored security summary back to Google Sheets. Triggers manually (or on an optional daily schedule). Loads the target Google…

Event trigger★★★★★ complexity32 nodesGoogle SheetsHTTP Request
Data & Sheets Trigger: Event Nodes: 32 Complexity: ★★★★★ Added:

This workflow corresponds to n8n.io template #16388 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

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 →

Download .json
{
  "id": "LcdfinE8leXWJ070",
  "name": "JWT Security Checker",
  "tags": [],
  "nodes": [
    {
      "id": "8b6d538b-0255-48dc-a1ec-b94b4fad749b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 592,
        "content": "## JWT Security Checker\n\n### How it works\n\n1. Triggers the workflow manually or on a schedule.\n2. Sets necessary variables for further processing.\n3. Reads endpoints from Google Sheets and filters active ones.\n4. Decodes JWTs and makes HTTP requests for various security checks.\n5. Analyzes results and writes them back to Google Sheets.\n\n### Setup steps\n\n- [ ] Configure Google Sheets credentials to access the necessary spreadsheet.\n- [ ] Set schedule trigger as needed for daily execution.\n- [ ] Ensure correct endpoint URLs are placed in the Google Sheets.\n\n### Customization\n\nThe schedule and endpoints sheet configuration can be customized to match specific needs or timing."
      },
      "typeVersion": 1
    },
    {
      "id": "2f877ee3-6f04-4d38-ac7d-fc625c5e93bd",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        560
      ],
      "parameters": {
        "color": 7,
        "height": 496,
        "content": "## Trigger workflow\n\nInitiates workflow either manually or on a schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "4e740484-fecd-435a-bdac-11ee15353a78",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        656
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "## Set variables\n\nSets essential variables including sheet IDs."
      },
      "typeVersion": 1
    },
    {
      "id": "e908c343-4e54-499b-a4a3-73071dcd0161",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        656
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 304,
        "content": "## Retrieve and filter endpoints\n\nReads endpoints from Google Sheets and filters active ones."
      },
      "typeVersion": 1
    },
    {
      "id": "e79bcc6a-f6ca-4dc3-a765-00eb9b5b4c56",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 576,
        "content": "## Endpoint processing loop\n\nLoops over each endpoint to process JWTs and perform HTTP requests."
      },
      "typeVersion": 1
    },
    {
      "id": "4f333687-6159-49a0-9549-dfd866c9df7a",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2000,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 656,
        "content": "## HTTP requests and status extraction\n\nSends HTTP requests for different token scenarios and extracts statuses."
      },
      "typeVersion": 1
    },
    {
      "id": "341b4557-5454-488f-8ab4-c001e6addcdb",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3120,
        336
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 624,
        "content": "## Results merging and analysis\n\nCombines all obtained statuses into comprehensive results for analysis."
      },
      "typeVersion": 1
    },
    {
      "id": "6c50cd84-8773-4240-a289-f2a3f34bc0c1",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3792,
        512
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "## Write final results\n\nWrites the processed results back to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "1cad0bd8-540b-4823-b287-711a04302e64",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3472,
        0
      ],
      "parameters": {
        "color": 7,
        "height": 304,
        "content": "## Failed token handling\n\nHandles cases where T1 HTTP requests fail."
      },
      "typeVersion": 1
    },
    {
      "id": "17b4ae7b-c77c-40ea-be11-17afb4962ab8",
      "name": "When Triggered Manually",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        608,
        688
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "acf798f3-31d1-4941-a8a0-25dab53e5912",
      "name": "When Daily at 08:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "disabled": true,
      "position": [
        608,
        880
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "a7a7f05b-14b8-46c3-997b-4b28169a8bb7",
      "name": "Read from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1152,
        784
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Sheet Variables').first().json.endpoints_sheet }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Sheet Variables').first().json.sheet_id }}"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "70030fe3-434c-43b2-a153-5811fb594e95",
      "name": "Loop Over Endpoint Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1600,
        784
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "d214bf62-746c-4f73-b4b7-55018b045a88",
      "name": "Decode JWT and Build Tokens",
      "type": "n8n-nodes-base.code",
      "position": [
        1824,
        512
      ],
      "parameters": {
        "jsCode": "const endpoint = $input.all()[0].json;\nconst token = (endpoint.token || '').trim();\nif (!token) throw new Error('No token for: ' + (endpoint.label || 'unknown'));\nconst parts = token.split('.');\nif (parts.length !== 3) throw new Error('Invalid JWT format for: ' + endpoint.label);\n\nconst decodeB64 = (str) => {\n  const padded = str.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice(0, (4 - str.length % 4) % 4);\n  return JSON.parse(Buffer.from(padded, 'base64').toString('utf8'));\n};\n\nconst header  = decodeB64(parts[0]);\nconst payload = decodeB64(parts[1]);\n\nconst b64url = (obj) => Buffer.from(JSON.stringify(obj))\n  .toString('base64').replace(/=/g, '').replace(/\\+/g, '-').replace(/\\//g, '_');\n\nconst noneToken = b64url({ alg: 'none', typ: 'JWT' }) + '.' +\n  b64url({ sub: 'attacker', role: 'admin', iss: payload.iss || 'test' }) + '.';\nconst tamperedToken = parts[0] + '.' +\n  b64url({ ...payload, role: 'admin', sub: 'attacker' }) + '.' + parts[2];\n\nreturn [{ json: {\n  label:     endpoint.label,\n  url:       endpoint.endpoint_url,\n  method:    (endpoint.method || 'GET').toUpperCase(),\n  alg:       header.alg || 'unknown',\n  has_exp:   !!payload.exp,\n  t1_header: 'Bearer ' + token,\n  t2_header: 'invalid',\n  t3_header: 'Bearer ' + tamperedToken,\n  t4_header: 'Bearer ' + noneToken,\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "862e35d0-989b-4d85-87bb-4a41cbff7b11",
      "name": "Analyze JWT Results",
      "type": "n8n-nodes-base.code",
      "position": [
        3616,
        640
      ],
      "parameters": {
        "jsCode": "const d = $input.first().json;\nconst s1 = d.t1_status, s2 = d.t2_status, s3 = d.t3_status, s4 = d.t4_status;\nconst { label, alg, has_exp } = d;\n\nconst findings = [];\nif (s1 !== 200) findings.push({ sev: 'HIGH',     msg: 'Valid token rejected (status ' + s1 + ')' });\nif (s2 === 200)  findings.push({ sev: 'HIGH',     msg: 'Endpoint accessible without auth' });\nif (s3 === 200)  findings.push({ sev: 'HIGH',     msg: 'Tampered token accepted' });\nif (s4 === 200)  findings.push({ sev: 'CRITICAL', msg: 'alg:none accepted - signature bypass' });\nif (!has_exp)    findings.push({ sev: 'MEDIUM',   msg: 'Token has no expiry (missing exp claim)' });\n\nconst rank = { CRITICAL: 4, HIGH: 3, MEDIUM: 2, LOW: 1, INFO: 0 };\nconst topSev = findings.length === 0 ? 'PASS' : findings.reduce((best, f) => rank[f.sev] > rank[best] ? f.sev : best, 'INFO');\n\nconst summary = findings.length === 0\n  ? label + ': all checks passed.'\n  : findings.length + ' issue(s) on ' + label + ': ' + findings.map(f => f.sev + ' - ' + f.msg).join('; ') + '.';\n\nreturn [{ json: {\n  timestamp:   new Date().toISOString(),\n  label,\n  risk_level:  topSev,\n  t1_valid:    s1 === 200 ? 'PASS' : 'FAIL',\n  t2_no_auth:  s2 !== 200 ? 'PASS' : 'FAIL',\n  t3_tampered: s3 !== 200 ? 'PASS' : 'FAIL',\n  t4_alg_none: s4 !== 200 ? 'PASS' : 'FAIL',\n  summary,\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "33704847-b40f-4788-835a-af9ee82a043a",
      "name": "Append to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3840,
        640
      ],
      "parameters": {
        "columns": {
          "value": {
            "alg": "={{ $json.alg }}",
            "label": "={{ $json.label }}",
            "summary": "={{ $json.summary }}",
            "findings": "={{ $json.findings }}",
            "t1_valid": "={{ $json.t1_valid }}",
            "timestamp": "={{ $json.timestamp }}",
            "exp_status": "={{ $json.exp_status }}",
            "risk_level": "={{ $json.risk_level }}",
            "t2_no_auth": "={{ $json.t2_no_auth }}",
            "test_valid": "={{ $json.test_valid }}",
            "t3_tampered": "={{ $json.t3_tampered }}",
            "t4_alg_none": "={{ $json.t4_alg_none }}",
            "endpoint_url": "={{ $json.endpoint_url }}",
            "test_no_auth": "={{ $json.test_no_auth }}",
            "test_alg_none": "={{ $json.test_alg_none }}",
            "test_tampered": "={{ $json.test_tampered }}",
            "sensitive_claims": "={{ $json.sensitive_claims }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false
            },
            {
              "id": "label",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "label",
              "defaultMatch": false
            },
            {
              "id": "risk_level",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "risk_level",
              "defaultMatch": false
            },
            {
              "id": "t1_valid",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "t1_valid",
              "defaultMatch": false
            },
            {
              "id": "t2_no_auth",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "t2_no_auth",
              "defaultMatch": false
            },
            {
              "id": "t3_tampered",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "t3_tampered",
              "defaultMatch": false
            },
            {
              "id": "t4_alg_none",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "t4_alg_none",
              "defaultMatch": false
            },
            {
              "id": "summary",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "summary",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Sheet Variables').first().json.results_sheet }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Sheet Variables').first().json.sheet_id }}"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "b8060be5-4117-48b4-b4cc-ddeb14642a5d",
      "name": "Validate Token via HTTP",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2048,
        512
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "={{ $json.method }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.t1_header }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "fb07f839-6d19-431e-9a2b-44d0bef6d2ae",
      "name": "HTTP Request No Auth",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2720,
        512
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "={{ $json.method }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.t2_header }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7cb21dd0-f522-455b-a43a-fdbb4b2d72bb",
      "name": "Tampered Token HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2720,
        704
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "={{ $json.method }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.t3_header }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f604fe9f-f18c-48af-b7a5-c8d163d28ff0",
      "name": "Algorithm None HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2720,
        896
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "={{ $json.method }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ $json.t4_header }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "6d98124d-5ffa-42d8-b582-9bc315b5ab43",
      "name": "Extract Valid Token Status",
      "type": "n8n-nodes-base.code",
      "position": [
        2272,
        512
      ],
      "parameters": {
        "jsCode": "const http = $input.first().json;\nconst meta = $('Decode JWT and Build Tokens').first().json;\nreturn [{ json: {\n  t1_status: http.statusCode,\n  label:     meta.label,\n  alg:       meta.alg,\n  has_exp:   meta.has_exp,\n  url:       meta.url,\n  method:    meta.method,\n  t2_header: meta.t2_header,\n  t3_header: meta.t3_header,\n  t4_header: meta.t4_header,\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "d12c76b6-d767-479e-a694-41035d50c3bc",
      "name": "Extract No Auth Status",
      "type": "n8n-nodes-base.code",
      "position": [
        2944,
        512
      ],
      "parameters": {
        "jsCode": "return [{ json: { t2_status: $input.first().json.statusCode } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "00a7c2e5-a7ee-4cdb-9704-c0c5ab024650",
      "name": "Extract Tampered Status",
      "type": "n8n-nodes-base.code",
      "position": [
        2944,
        704
      ],
      "parameters": {
        "jsCode": "return [{ json: { t3_status: $input.first().json.statusCode } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "462ef189-5b1a-43f3-b6ab-1c3fb63753ee",
      "name": "Extract Alg None Status",
      "type": "n8n-nodes-base.code",
      "position": [
        2944,
        896
      ],
      "parameters": {
        "jsCode": "return [{ json: { t4_status: $input.first().json.statusCode } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e791614f-b3a5-4774-a1c5-d1f87f992878",
      "name": "Merge Valid and No Auth Results",
      "type": "n8n-nodes-base.merge",
      "position": [
        3168,
        448
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "8f0eca9a-06b4-44b9-917d-b402931e834c",
      "name": "Merge Tampered and Alg Results",
      "type": "n8n-nodes-base.merge",
      "position": [
        3168,
        800
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "d630435b-9b0a-4c5c-88e0-51fa74299baf",
      "name": "Merge All JWT Results",
      "type": "n8n-nodes-base.merge",
      "position": [
        3392,
        640
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3
    },
    {
      "id": "9b8e7faf-86ce-4e6d-804e-ba266d832916",
      "name": "Check Valid Token Pass",
      "type": "n8n-nodes-base.if",
      "position": [
        2496,
        512
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.t1_status }}",
              "rightValue": 200
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "19fd3577-a0a6-4fce-9729-10993667af72",
      "name": "Handle Failed Token Validation",
      "type": "n8n-nodes-base.code",
      "position": [
        3520,
        128
      ],
      "parameters": {
        "jsCode": "const d = $input.first().json;\nreturn [{ json: {\n  timestamp:   new Date().toISOString(),\n  label:       d.label,\n  risk_level:  'ERROR',\n  t1_valid:    'FAIL',\n  t2_no_auth:  'SKIP',\n  t3_tampered: 'SKIP',\n  t4_alg_none: 'SKIP',\n  summary:     d.label + ': T1 FAIL (HTTP ' + d.t1_status + ') \u2014 valid token rejected. Check token expiry or endpoint URL. Security tests skipped.',\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "0ee1fb5b-cdee-4690-a4a1-c9af5892ac97",
      "name": "Set Sheet Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        880,
        784
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1",
              "name": "sheet_id",
              "type": "string",
              "value": "YOUR_GOOGLE_SHEET_ID"
            },
            {
              "id": "2",
              "name": "endpoints_sheet",
              "type": "string",
              "value": "Sheet1"
            },
            {
              "id": "3",
              "name": "results_sheet",
              "type": "string",
              "value": "Sheet2"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ed8312a0-e615-4952-8790-515186b9d0b6",
      "name": "Filter Active Endpoints",
      "type": "n8n-nodes-base.filter",
      "position": [
        1376,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.active }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "15f2e1e8-3df3-477e-b291-e1877e35dee2",
      "name": "Sticky \u2014 Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        624
      ],
      "parameters": {
        "width": 820,
        "height": 564,
        "content": "## Setup Google Sheet\n\n**1. Create a sheet with two tabs:\n\n`Sheet1` (Endpoints) columns:\n`label | endpoint_url | method | token | active`\n\nSet `active` to `TRUE` to include an endpoint, `FALSE` to skip it.\n\n`Sheet2` (Results) columns:\n`timestamp | label | risk_level | t1_valid | t2_no_auth | t3_tampered | t4_alg_none | summary`\n\n**2. Credentials**\nConnect a Google Service Account to both Google Sheets nodes (Read Endpoints + Write Results).\n\n**3. Configure Set Variables node**\nOpen the `Set Variables` node and update:\n- `sheet_id` \u2014 ID from your Google Sheet URL\n- `endpoints_sheet` \u2014 name of the Endpoints tab (default: Sheet1)\n- `results_sheet` \u2014 name of the Results tab (default: Sheet2)\n\n**Example of endpoints sheet:**\n| Test endpoint | https://example.com/secure | GET | eyJhbG..AxQ | TRUE |"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "d85c3ed1-7a31-4db4-8603-b366026122b6",
  "nodeGroups": [],
  "connections": {
    "Append to Sheets": {
      "main": [
        [
          {
            "node": "Loop Over Endpoint Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read from Sheets": {
      "main": [
        [
          {
            "node": "Filter Active Endpoints",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze JWT Results": {
      "main": [
        [
          {
            "node": "Append to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Sheet Variables": {
      "main": [
        [
          {
            "node": "Read from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Daily at 08:00": {
      "main": [
        [
          {
            "node": "Set Sheet Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request No Auth": {
      "main": [
        [
          {
            "node": "Extract No Auth Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All JWT Results": {
      "main": [
        [
          {
            "node": "Analyze JWT Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Valid Token Pass": {
      "main": [
        [
          {
            "node": "HTTP Request No Auth",
            "type": "main",
            "index": 0
          },
          {
            "node": "Tampered Token HTTP Request",
            "type": "main",
            "index": 0
          },
          {
            "node": "Algorithm None HTTP Request",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Valid and No Auth Results",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Failed Token Validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract No Auth Status": {
      "main": [
        [
          {
            "node": "Merge Valid and No Auth Results",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Extract Alg None Status": {
      "main": [
        [
          {
            "node": "Merge Tampered and Alg Results",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Extract Tampered Status": {
      "main": [
        [
          {
            "node": "Merge Tampered and Alg Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Active Endpoints": {
      "main": [
        [
          {
            "node": "Loop Over Endpoint Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Token via HTTP": {
      "main": [
        [
          {
            "node": "Extract Valid Token Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Triggered Manually": {
      "main": [
        [
          {
            "node": "Set Sheet Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Valid Token Status": {
      "main": [
        [
          {
            "node": "Check Valid Token Pass",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Endpoint Batches": {
      "main": [
        [],
        [
          {
            "node": "Decode JWT and Build Tokens",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Algorithm None HTTP Request": {
      "main": [
        [
          {
            "node": "Extract Alg None Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode JWT and Build Tokens": {
      "main": [
        [
          {
            "node": "Validate Token via HTTP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tampered Token HTTP Request": {
      "main": [
        [
          {
            "node": "Extract Tampered Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Failed Token Validation": {
      "main": [
        [
          {
            "node": "Append to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Tampered and Alg Results": {
      "main": [
        [
          {
            "node": "Merge All JWT Results",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Valid and No Auth Results": {
      "main": [
        [
          {
            "node": "Merge All JWT Results",
            "type": "main",
            "index": 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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow reads API endpoints and JWTs from Google Sheets, tests each endpoint with multiple token scenarios using HTTP requests, and writes a risk-scored security summary back to Google Sheets. Triggers manually (or on an optional daily schedule). Loads the target Google…

Source: https://n8n.io/workflows/16388/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

TrackCollect_deeper. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 80 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +1
Data & Sheets

This template is ideal for solo store owners, eCommerce marketers, automation beginners, or anyone using Shopify and Gmail who wants to recover lost revenue without coding.

HTTP Request, Gmail, Twilio +3
Data & Sheets

PCN. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 60 nodes.

Google Sheets, HTTP Request, @N Octo N/N8N Nodes Json Database +3
Data & Sheets

The workflow automates the process of gathering extensive keyword data for a "Main Keyword." It starts by reading initial parameters from a Google Sheets template, creates a new dedicated Google Sheet

Google Sheets, Google Drive, HTTP Request
Data & Sheets

cdp_router. Uses gmailTrigger, telegramTrigger, googleSheets, httpRequest. Event-driven trigger; 53 nodes.

Gmail Trigger, Telegram Trigger, Google Sheets +4