Gestion automatisée des jetons Zalo OA, intégrant OAuth et Webhook
Ceci est unEngineering, DevOps, Multimodal AIworkflow d'automatisation du domainecontenant 10 nœuds.Utilise principalement des nœuds comme Set, Code, Webhook, HttpRequest, ScheduleTrigger. Gestion automatisée des jetons Zalo OA, intégrant OAuth et Webhook
- •Point de terminaison HTTP Webhook (généré automatiquement par n8n)
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (10)
Catégorie
{
"meta": {
"instanceId": "9a562c06a632241f66aadd52a495ad98e76b760ef5cfce9c319a4759c47cd94e"
},
"nodes": [
{
"id": "df8fb435-f49e-4dec-8ed5-0b5b536ceab3",
"name": "Stockage dans SD et transmission du jeton",
"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": "Rafraîchir le jeton (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": "Déclencheur planifié",
"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": "Exécuter_Node",
"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": "Nettoyer les données statiques 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": "Définir le jeton de rafraîchissement et l'ID d'application",
"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": "Charger dans les données statiques",
"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": "Charger le jeton d'accès",
"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": "Note autocollante",
"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
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - Ingénierie, DevOps, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
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.
Partager ce workflow