OAuth 및 Webhook 통합 자동화 Zalo OA 토큰 관리
이것은Engineering, DevOps, Multimodal AI분야의자동화 워크플로우로, 10개의 노드를 포함합니다.주로 Set, Code, Webhook, HttpRequest, ScheduleTrigger 등의 노드를 사용하며. OAuth 및 Webhook을 통합한 자동화 Zalo OA 토큰 관리
- •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에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
중급 - 엔지니어링, 데브옵스, 멀티모달 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.
이 워크플로우 공유