8
n8n 中文网amn8n.com

OAuth令牌管理系统(Airtable存储)

高级

这是一个Engineering领域的自动化工作流,包含 20 个节点。主要使用 If, Code, Webhook, Airtable, HttpRequest 等节点。 OAuth令牌管理系统(Airtable存储)

前置要求
  • HTTP Webhook 端点(n8n 会自动生成)
  • Airtable API Key
  • 可能需要目标 API 的认证凭证

分类

工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "meta": {
    "instanceId": "2e491e733aabd347ba9dbe351de2eb0282b95dd5f327bc32034e70bc5642d897"
  },
  "nodes": [
    {
      "id": "1529173e-b4ae-4352-a378-a327c39e7fed",
      "name": "成功",
      "type": "n8n-nodes-base.if",
      "position": [
        448,
        -48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "faa449f2-815c-41fa-8378-e93093ad10d7",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.success }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "140b3700-3721-4e41-b87c-8df70e995bc4",
      "name": "验证失败",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        672,
        48
      ],
      "parameters": {
        "options": {
          "responseCode": 401
        },
        "respondWith": "json",
        "responseBody": "={\n  \"success\": false,\n  \"error\": \"{{ $('validator').first().json.reason }}\"\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "4715c17e-56d8-49f5-bcce-7f5b6f822f49",
      "name": "便签2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        -304
      ],
      "parameters": {
        "color": 6,
        "width": 260,
        "height": 308,
        "content": "## 数据库示例"
      },
      "typeVersion": 1
    },
    {
      "id": "722d92c2-445c-4c0a-9e06-a58dbc075907",
      "name": "密钥验证",
      "type": "n8n-nodes-base.if",
      "position": [
        1120,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "2e4151fc-f513-4a1d-8e42-c77857de22bc",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.secret }}",
              "rightValue": "={{ $('client receiver').item.json.body.client_secret }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a02e3055-eb51-4fec-a429-d8349e388fe4",
      "name": "无效客户端",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1120,
        -48
      ],
      "parameters": {
        "options": {
          "responseCode": 400
        },
        "respondWith": "json",
        "responseBody": "{\n\"success\": false,\n\"error\": \"Invalid client id\"\n}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "729d6799-6f74-457c-aac5-ca651e10f170",
      "name": "无效密钥",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1344,
        -144
      ],
      "parameters": {
        "options": {
          "responseCode": 401
        },
        "respondWith": "json",
        "responseBody": "{\n\"success\": false,\n\"error\": \"Invalid client secret\"\n}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "b94ab331-23c2-473d-afdc-e591b89b38e0",
      "name": "生成令牌",
      "type": "n8n-nodes-base.code",
      "position": [
        1344,
        -336
      ],
      "parameters": {
        "jsCode": "function generateLongToken(length) {\n  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n  let token = '';\n  for (let i = 0; i < length; i++) {\n    token += chars.charAt(Math.floor(Math.random() * chars.length));\n  }\n  return token;\n}\n\nconst token = generateLongToken(32);\n\nreturn [\n  {\n    json: {\n      token\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "204e04af-34a7-4824-b107-4cc3e89199e3",
      "name": "客户端存在",
      "type": "n8n-nodes-base.if",
      "position": [
        896,
        -144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6f16470a-aae4-4647-850e-332284b00a9f",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e366461a-ece5-47d1-b5de-ea29aa1846ca",
      "name": "验证器",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        -48
      ],
      "parameters": {
        "jsCode": "const input = $json;\n\nconst body = input.body || {};\n\n// Allowed keys\nconst allowedKeys = ['client_id', 'client_secret'];\n\n// Check required keys\nfor (const key of allowedKeys) {\n  if (!body.hasOwnProperty(key)) {\n    return [{ json: { success: false, reason: `Missing '${key}' in body` } }];\n  }\n}\n\n// Check for extra keys\nconst extraKeys = Object.keys(body).filter(k => !allowedKeys.includes(k));\nif (extraKeys.length > 0) {\n  return [{ json: { success: false, reason: `Body must contain only 'client_id' and 'client_secret', found extra key(s): ${extraKeys.join(', ')}` } }];\n}\n\n// All good\nreturn [{ json: { success: true } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "b7ea9e5f-d097-4ff7-b165-ee1560bb054d",
      "name": "客户端接收器",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        -48
      ],
      "webhookId": "e502851b-c6a5-4de2-94c7-c2320c73f203",
      "parameters": {
        "path": "token-refresher",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "70e09e1b-336a-4756-af23-aa4a0636e854",
      "name": "获取客户端ID",
      "type": "n8n-nodes-base.airtable",
      "position": [
        672,
        -144
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appbw5TEhn8xIxxXR",
          "cachedResultUrl": "https://airtable.com/appbw5TEhn8xIxxXR",
          "cachedResultName": "Testing Bearer Auth "
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tblK2jv4hLOsaKM3m",
          "cachedResultUrl": "https://airtable.com/appbw5TEhn8xIxxXR/tblK2jv4hLOsaKM3m",
          "cachedResultName": "Client IDs"
        },
        "options": {},
        "operation": "search",
        "filterByFormula": "={client} = \"{{ $('client receiver').item.json.body.client_id }}\""
      },
      "credentials": {
        "airtableTokenApi": {
          "id": "SCfOTbIrHHSfAWgr",
          "name": "Testing Bearer Auth "
        }
      },
      "typeVersion": 2.1,
      "alwaysOutputData": true
    },
    {
      "id": "d5c9d779-5805-45a0-affd-a683a17391ac",
      "name": "创建令牌",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1568,
        -336
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appbw5TEhn8xIxxXR",
          "cachedResultUrl": "https://airtable.com/appbw5TEhn8xIxxXR",
          "cachedResultName": "Testing Bearer Auth "
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tblnqvjl4U2t9OMQD",
          "cachedResultUrl": "https://airtable.com/appbw5TEhn8xIxxXR/tblnqvjl4U2t9OMQD",
          "cachedResultName": "Tokens"
        },
        "columns": {
          "value": {
            "Token ID": "={{ $json.token }}",
            "Client IDs": "={{ [$('client receiver').item.json.body.client_id] }}",
            "Token Type": "Bearer",
            "Creation Date": "={{ $now }}"
          },
          "schema": [
            {
              "id": "Token ID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Token ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Token Type",
              "type": "options",
              "display": true,
              "options": [
                {
                  "name": "Bearer",
                  "value": "Bearer"
                }
              ],
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Token Type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Expiration Date",
              "type": "dateTime",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Expiration Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Issued To",
              "type": "array",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Issued To",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Creation Date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Creation Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Is Active",
              "type": "boolean",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Is Active",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Days Until Expiration",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Days Until Expiration",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client IDs",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Client IDs",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": true
        },
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "id": "SCfOTbIrHHSfAWgr",
          "name": "Testing Bearer Auth "
        }
      },
      "typeVersion": 2.1,
      "alwaysOutputData": true
    },
    {
      "id": "09da5fce-3635-4125-903b-a55ca93a5b4b",
      "name": "响应",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1792,
        -336
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n    \"access_token\": \"{{ $('generate token').item.json.token }}\",\n    \"expires_in\": 3600,\n    \"token_type\": \"{{ $json.fields['Token Type'] }}\"\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "325443c4-31b4-472f-ab2c-e606776466ba",
      "name": "其他方法",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        272
      ],
      "webhookId": "3a898a00-f298-4d47-b1d0-26d2eb6d1898",
      "parameters": {
        "path": "test-jobs",
        "options": {},
        "httpMethod": [
          "DELETE",
          "HEAD",
          "PATCH",
          "PUT",
          "GET"
        ],
        "responseMode": "responseNode",
        "multipleMethods": true
      },
      "typeVersion": 2
    },
    {
      "id": "8b407e94-1e92-4882-872f-f6b2e6e60673",
      "name": "405 错误",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        208,
        320
      ],
      "parameters": {
        "options": {
          "responseCode": 405
        },
        "respondWith": "json",
        "responseBody": "{\n  \"error\": \"Use POST request instead\"\n}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "7bc3accc-791d-4f8a-8f14-80f2d3d4ddf9",
      "name": "点击\"执行工作流\"时",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        16,
        -448
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d94ffe0e-95f7-459c-a837-a08b9ac3d87f",
      "name": "发起请求",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        240,
        -448
      ],
      "parameters": {
        "url": "https://localhost:8080/webhook/token-refresher",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n    \"client_id\": \"client_a_1234567890abcdef\",\n    \"client_secret\": \"secret_a_abcdef1234567890\"\n\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "b9ea6991-ba49-49f0-bffb-5cc807eedb94",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -512
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 220,
        "content": "## 测试请求"
      },
      "typeVersion": 1
    },
    {
      "id": "e8814551-20d1-4114-b691-0a45cbf61086",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        208
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 280,
        "content": "## HTTP 方法处理器"
      },
      "typeVersion": 1
    },
    {
      "id": "db9c1b3f-00ba-40fe-8e9c-f900be065940",
      "name": "便签3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        -512
      ],
      "parameters": {
        "color": 4,
        "width": 580,
        "height": 1656,
        "content": "## OAuth 令牌生成器和验证器"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {
    "client receiver": [
      {
        "body": {
          "client_id": "client_a_1234567890abcdef",
          "client_secret": "secret_a_abcdef1234567890"
        },
        "query": {},
        "params": {},
        "headers": {
          "host": "api.hirempire.com",
          "accept": "*/*",
          "x-real-ip": "102.190.108.154",
          "user-agent": "PostmanRuntime/7.44.1",
          "content-type": "application/json",
          "cache-control": "no-cache",
          "postman-token": "d4f91538-8577-4892-98fe-e58cdf6279d5",
          "content-length": "103",
          "accept-encoding": "gzip, deflate, br",
          "x-forwarded-for": "102.190.108.154",
          "x-forwarded-host": "api.hirempire.com",
          "x-forwarded-port": "443",
          "x-forwarded-proto": "https",
          "x-forwarded-server": "483fb0fb5aec"
        },
        "webhookUrl": "https://api.hirempire.com/v1/token-refresher",
        "executionMode": "production"
      }
    ]
  },
  "connections": {
    "success": {
      "main": [
        [
          {
            "node": "get client id",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "validation failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "validator": {
      "main": [
        [
          {
            "node": "success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create token": {
      "main": [
        [
          {
            "node": "respond ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Other methods": {
      "main": [
        [
          {
            "node": "405 Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "405 Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "405 Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "405 Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "405 Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "client exists": {
      "main": [
        [
          {
            "node": "secret validation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "invalid client",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get client id": {
      "main": [
        [
          {
            "node": "client exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "generate token": {
      "main": [
        [
          {
            "node": "create token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "client receiver": {
      "main": [
        [
          {
            "node": "validator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "secret validation": {
      "main": [
        [
          {
            "node": "generate token",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "invalid secret",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Execute workflow’": {
      "main": [
        [
          {
            "node": "Make a request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 工程

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量20
分类1
节点类型8
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

外部链接
在 n8n.io 查看

分享此工作流