Zalo OA トークン管理を自動化し、OAuth と Webhook を統合
これはEngineering, DevOps, Multimodal AI分野の自動化ワークフローで、10個のノードを含みます。主にSet, Code, Webhook, HttpRequest, ScheduleTriggerなどのノードを使用。 Zalo OA トークン管理を自動化し、OAuth と Webhook を統合します
- •HTTP Webhookエンドポイント(n8nが自動生成)
- •ターゲットAPIの認証情報が必要な場合あり
{
"meta": {
"instanceId": "9a562c06a632241f66aadd52a495ad98e76b760ef5cfce9c319a4759c47cd94e"
},
"nodes": [
{
"id": "df8fb435-f49e-4dec-8ed5-0b5b536ceab3",
"name": "SD保存&トークン受け渡し",
"type": "n8n-nodes-base.code",
"position": [
336,
0
],
"parameters": {
"jsCode": "const sd = $getWorkflowStaticData('global');\nconst r = $input.first().json || {};\nconst now = Date.now();\nsd.zalo = sd.zalo || {};\nif (r.access_token) sd.zalo.access_token = r.access_token;\nif (r.refresh_token) sd.zalo.refresh_token = r.refresh_token;\nconst exp = parseInt(r.expires_in, 10);\nif (!isNaN(exp)) sd.zalo.access_expires_at = now + exp * 1000;\nconst rExp = parseInt(r.refresh_token_expires_in, 10);\nif (!isNaN(rExp)) sd.zalo.refresh_expires_at = now + rExp * 1000;\n// IMPORTANT: return the refreshed token in the CURRENT ITEM\nreturn [{ json: {\n source: \"refreshed\",\n access_token: sd.zalo.access_token,\n access_expires_at: sd.zalo.access_expires_at\n}}];"
},
"typeVersion": 2
},
{
"id": "5676141d-7a9e-4872-900a-48d7a7c59cc2",
"name": "トークン更新(Zalo v4)",
"type": "n8n-nodes-base.httpRequest",
"position": [
64,
0
],
"parameters": {
"url": "https://oauth.zaloapp.com/v4/oa/access_token",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendBody": true,
"contentType": "form-urlencoded",
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "refresh_token",
"value": "={{ $json.refresh_token }}"
},
{
"name": "app_id",
"value": "={{ $json.app_id }}"
},
{
"name": "grant_type",
"value": "refresh_token"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "secret_key",
"value": "={{ $('Set Refresh Token and App ID').item.json.secret_key }}"
}
]
}
},
"typeVersion": 3
},
{
"id": "65bbbd29-24ae-475d-80d2-674da63db2eb",
"name": "スケジュールトリガー",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-848,
16
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 12
}
]
}
},
"typeVersion": 1.2
},
{
"id": "62cbb107-ef08-4b09-b061-ecb9ae02c626",
"name": "ノード実行",
"type": "n8n-nodes-base.webhook",
"position": [
-848,
-176
],
"webhookId": "99397651-be96-4106-9017-3e62f0ddf03e",
"parameters": {
"path": "99397651-be96-4106-9017-3e62f0ddf03e",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "21029f3c-0080-4950-80f5-965cc4259239",
"name": "Zalo静的データ消去",
"type": "n8n-nodes-base.code",
"position": [
-608,
-176
],
"parameters": {
"jsCode": "const sd = $getWorkflowStaticData('global');\ndelete sd['zalo'];\nreturn [{ json: { cleared: true } }];\n"
},
"typeVersion": 2
},
{
"id": "d80a21bf-9e3a-4125-9657-38520907f78a",
"name": "更新トークンとアプリID設定",
"type": "n8n-nodes-base.set",
"position": [
-384,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "125b6083-9cac-4c88-b1c9-968cfe06a5d3",
"name": "refresh_token",
"type": "string",
"value": "refresh_token_initial_refesh_token"
},
{
"id": "d8e706c2-9609-4780-95d7-e3c5297a0cee",
"name": "app_id",
"type": "string",
"value": "your_oa_app_id"
},
{
"id": "8230a16f-3100-4fdb-9125-317f1c63fd23",
"name": "secret_key",
"type": "string",
"value": "your_app_secret_key"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "37a79c0a-08c2-4a9b-9655-aa2e49c2f36c",
"name": "静的データ読み込み",
"type": "n8n-nodes-base.code",
"position": [
-176,
0
],
"parameters": {
"jsCode": "const sd = $getWorkflowStaticData('global');\nconst now = Date.now();\nconst bufferMs = 90 * 1000; // refresh 90s early\nsd.zalo = sd.zalo || {};\nconsole.log('new code #### here this is',sd.zalo);\n// Seed refresh token on very first run\nif (!sd.zalo.refresh_token) {\n sd.zalo.refresh_token = $input.first().json.refresh_token;\n}\n\nconst hasAccess = !!sd.zalo.access_token;\nconst notExpired = !!sd.zalo.access_expires_at && (sd.zalo.access_expires_at - bufferMs) > now;\nconst needs_refresh = !(hasAccess && notExpired);\n\nreturn [{\n json: {\n needs_refresh,\n access_token: sd.zalo.access_token || null,\n access_expires_at: sd.zalo.access_expires_at || null,\n refresh_token: sd.zalo.refresh_token || null,\n app_id: $input.first().json.app_id\n }\n}];"
},
"typeVersion": 2
},
{
"id": "25f68c0d-9eef-43be-accc-60bae7d62065",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-848,
240
],
"webhookId": "5afc66e9-136e-4fb2-9263-9aaa1c1037ef",
"parameters": {
"path": "zalo-intergration-v1",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "e96e8fdf-e031-4afc-b1ab-b6f1b9837158",
"name": "アクセストークン読み込み",
"type": "n8n-nodes-base.code",
"position": [
-592,
240
],
"parameters": {
"jsCode": "const sd = $getWorkflowStaticData('global');\nsd.zalo = sd.zalo || {};\nreturn [{\n json: {\n access_token: sd.zalo.access_token || null,\n access_expires_at: sd.zalo.access_expires_at || null,\n refresh_token: sd.zalo.refresh_token || null,\n }\n}];"
},
"typeVersion": 2
},
{
"id": "43e752b8-ec85-4764-addb-71383e69217d",
"name": "付箋ノート",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1856,
-848
],
"parameters": {
"width": 944,
"height": 1712,
"content": "# Zalo OA Token Auto-Refresh (n8n)\n\n## What this workflow does\n- Maintains a fresh Zalo OA access token using Workflow Static Data (global).\n- Supports both scheduled refresh and a manual “reset & re-seed” path.\n- Exposes a lightweight webhook to read the currently cached token for other integrations.\n\n---\n\n## High-level flow\nSchedule Trigger → Set Refresh Token & App ID → Load to Static Data → Refresh Token (Zalo v4) → Store to SD & Pass token\n\nManual reset path: Execute_Node (Webhook) → Clean Zalo Static Data → Set Refresh Token & App ID → … (continues flow above)\n\nToken peek path: Webhook (zalo-intergration-v1) → Load Access Token (returns cached token)\n\n---\n\n## Node-by-node\n\n### 1) Schedule Trigger\nRuns the auto-refresh flow on a fixed interval (every 12 hours) so the access token stays valid.\n\n### 2) Execute_Node (Webhook)\nManual entry point to trigger a reset of cached tokens during testing or when rotating credentials.\n\n### 3) Clean Zalo Static Data\nClears the token cache from Workflow Static Data so the next run re-seeds and refreshes from provided inputs.\n\n### 4) Set Refresh Token and App ID\nProvides the required identifiers and secrets to the flow (refresh token, app ID, secret key). \nTip: In production, reference environment variables instead of hardcoding.\n\n### 5) Load to Static Data\nInitializes the token cache on first run, checks if a valid access token already exists, and flags whether a refresh is needed (early-refresh buffer applied). \nNote: With the current wiring, the flow proceeds to refresh on every run.\n\n### 6) Refresh Token (Zalo v4)\nCalls Zalo OAuth to exchange the refresh token for a new access token and returns updated expiry information.\n\n### 7) Store to SD & Pass token\nPersists the latest token and expiry timestamps into Workflow Static Data and passes the current access token forward for immediate downstream use.\n\n### 8) Webhook (zalo-intergration-v1)\nSimple endpoint to request whatever token is currently cached (useful for other services/workflows).\n\n### 9) Load Access Token\nReads the cached access token and its expiry from Workflow Static Data and returns them to the caller of the integration webhook.\n\n---\n\n## Behavior & usage notes\n- The token cache is scoped to this workflow. Other workflows should call this one or use the integration webhook to retrieve the token.\n- An early-refresh buffer reduces the chance of token expiry during active API calls.\n- Secure the manual reset webhook (e.g., IP allowlist or secret) and move sensitive values to environment variables.\n- Optional optimization: insert an IF condition after “Load to Static Data” to skip the refresh call when the cached token is still valid.\n"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"25f68c0d-9eef-43be-accc-60bae7d62065": {
"main": [
[
{
"node": "e96e8fdf-e031-4afc-b1ab-b6f1b9837158",
"type": "main",
"index": 0
}
]
]
},
"62cbb107-ef08-4b09-b061-ecb9ae02c626": {
"main": [
[
{
"node": "21029f3c-0080-4950-80f5-965cc4259239",
"type": "main",
"index": 0
}
]
]
},
"65bbbd29-24ae-475d-80d2-674da63db2eb": {
"main": [
[
{
"node": "d80a21bf-9e3a-4125-9657-38520907f78a",
"type": "main",
"index": 0
}
]
]
},
"37a79c0a-08c2-4a9b-9655-aa2e49c2f36c": {
"main": [
[
{
"node": "5676141d-7a9e-4872-900a-48d7a7c59cc2",
"type": "main",
"index": 0
}
]
]
},
"21029f3c-0080-4950-80f5-965cc4259239": {
"main": [
[
{
"node": "d80a21bf-9e3a-4125-9657-38520907f78a",
"type": "main",
"index": 0
}
]
]
},
"5676141d-7a9e-4872-900a-48d7a7c59cc2": {
"main": [
[
{
"node": "df8fb435-f49e-4dec-8ed5-0b5b536ceab3",
"type": "main",
"index": 0
}
]
]
},
"d80a21bf-9e3a-4125-9657-38520907f78a": {
"main": [
[
{
"node": "37a79c0a-08c2-4a9b-9655-aa2e49c2f36c",
"type": "main",
"index": 0
}
]
]
}
}
}このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級 - エンジニアリング, DevOps, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
Le Nguyen
@leeseiferSalesforce Architect with 10+ years of experience in CRM, integrations, and automation. Skilled in Apex, LWC, REST APIs, and full-stack dev (JavaScript, .NET). I build secure, scalable workflows in n8n—connecting Salesforce, Stripe, and more. Passionate about lead scoring, data sync, and secure field masking. Certified Application Architect with deep expertise in platform, integration, and data architecture.
このワークフローを共有