{ "id": "IYgbtNpyB4E6Jbxo", "meta": { "instanceId": "35ae520798f87e479496aa54e1a1f89ffdf43eee77986511d08258a12b1edc98", "templateCredsSetupCompleted": true }, "name": "2. Refresh Pipedrive tokens", "tags": [], "nodes": [ { "id": "2b66edcd-c71a-4dac-971f-deb1b09ef85b", "name": "Stop and Error", "type": "n8n-nodes-base.stopAndError", "position": [ 1460, -80 ], "parameters": { "errorMessage": "Token refresh failed" }, "typeVersion": 1, "alwaysOutputData": false }, { "id": "b48d6760-766e-4b39-be35-89de7dc3ab5e", "name": "Sticky Note", "type": "n8n-nodes-base.stickyNote", "position": [ 60, -300 ], "parameters": { "color": 5, "width": 872, "height": 97, "content": "## Step 2:\nCreate a workflow to refresh your access token when the access token requires a refresh." }, "typeVersion": 1 }, { "id": "6119eef3-9ffa-45a1-b238-412738e7529e", "name": "Sticky Note1", "type": "n8n-nodes-base.stickyNote", "position": [ 280, -80 ], "parameters": { "height": 211, "content": "\n\n\n\n\n\n\n\nPost unique data to identify your row in Database and be able to fetch the existing access and refresh token" }, "typeVersion": 1 }, { "id": "2d76be21-95e1-4747-b761-126b133e8264", "name": "Sticky Note2", "type": "n8n-nodes-base.stickyNote", "position": [ 980, -220 ], "parameters": { "content": "## Get token from pipedrive" }, "typeVersion": 1 }, { "id": "9a44eb63-9d31-4b24-9171-1f9a828a5c52", "name": "Sticky Note3", "type": "n8n-nodes-base.stickyNote", "position": [ 100, -740 ], "parameters": { "color": 5, "width": 995, "height": 82, "content": "## Step 1:\nSave Refresh token and Access token to DB when authenticated by user and installed. " }, "typeVersion": 1 }, { "id": "f3247e6a-7c1c-4479-9f83-f3bc4146f254", "name": "Insert", "type": "n8n-nodes-base.supabase", "position": [ 1600, -660 ], "parameters": { "tableId": "App_tok", "fieldsUi": { "fieldValues": [ { "fieldId": "ref_token", "fieldValue": "={{ $node[\"Generate Refresh Token from authcode\"].json[\"body\"][\"refresh_token\"] }}" }, { "fieldId": "acc_token", "fieldValue": "={{ $node[\"Generate Refresh Token from authcode\"].json[\"body\"][\"access_token\"] }}" }, { "fieldId": "Platform", "fieldValue": "Pipedrive" }, { "fieldId": "created_at", "fieldValue": "={{$now.toUTC().toString()}}" }, { "fieldId": "updated_at", "fieldValue": "={{$now.toUTC().toString()}}" } ] } }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1 }, { "id": "f7ad45d0-7055-45f4-9971-031ffebfdbda", "name": "Sticky Note4", "type": "n8n-nodes-base.stickyNote", "position": [ 500, -640 ], "parameters": { "content": "You can also use SET NODE + tobase64 function as done in step 2" }, "typeVersion": 1 }, { "id": "e14e2dac-e84b-475f-a01b-14bb723eedc8", "name": "Sticky Note5", "type": "n8n-nodes-base.stickyNote", "position": [ 100, 200 ], "parameters": { "color": 5, "width": 1644, "height": 80, "content": "## Step 3:\nMake an actual API call. In this example, we are using search person API. Please refer to Pipedrive API documentation for your specific use case. " }, "typeVersion": 1 }, { "id": "b450c928-e0e4-4f49-829e-03b61828d4d9", "name": "Get Pipedrive Token", "type": "n8n-nodes-base.supabase", "position": [ 600, 660 ], "parameters": { "filters": { "conditions": [ { "keyName": "Platform", "keyValue": "Pipedrive" }, { "keyName": "AppId", "keyValue": "57db0bab2932f657" } ] }, "tableId": "App_tok", "operation": "get" }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1 }, { "id": "f92a957a-d0ef-4037-8657-74e7fe74fe6d", "name": "Get contact from Pipedrive", "type": "n8n-nodes-base.httpRequest", "position": [ 900, 660 ], "parameters": { "url": "=https://priyajain-sandbox.pipedrive.com/api/v2/persons/search?fields=email&term={{ $node[\"Receive request\"].json[\"body\"][\"person\"][\"email\"] }}", "options": { "response": { "response": { "fullResponse": true } } }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Accept", "value": "application/json" }, { "name": "Authorization", "value": "=Bearer {{ $node[\"Get Pipedrive Token\"].json[\"acc_token\"] }}" } ] } }, "typeVersion": 4, "continueOnFail": true, "alwaysOutputData": false }, { "id": "bff21156-3da0-4cf3-b3de-c24d8abe7577", "name": "Access Token Invalid", "type": "n8n-nodes-base.if", "position": [ 1160, 700 ], "parameters": { "conditions": { "boolean": [ { "value1": "={{ $json[\"error\"][\"message\"].includes(\"Invalid token: access token is invalid\") }}", "value2": "={{ true }}" } ] }, "combineOperation": "any" }, "typeVersion": 1 }, { "id": "9fd832b1-2af9-48c2-9d57-86a9f34bdd78", "name": "Success", "type": "n8n-nodes-base.respondToWebhook", "position": [ 1440, 720 ], "parameters": { "options": { "responseCode": 200 }, "respondWith": "json", "responseBody": "={{ $node[\"Get contact from Pipedrive\"].json[\"body\"][\"data\"][\"items\"][\"0\"][\"item\"][\"name\"] }}" }, "typeVersion": 1 }, { "id": "daf33b32-ff7b-4d7e-8fd0-d54dfaddf405", "name": "Refresh Access Token", "type": "n8n-nodes-base.httpRequest", "position": [ 1360, 320 ], "parameters": { "url": "http://localhost:5678/webhook/937a8843-a28a-400a-b473-bdc598366fa0", "method": "POST", "options": {}, "jsonBody": "{\n\n \"appId\":\"57db0bab2932f657\"\n\n}", "sendBody": true, "specifyBody": "json", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth" }, "credentials": { "httpBasicAuth": { "id": "E2RYFiR9PotuglZv", "name": "PJ demo" } }, "typeVersion": 4.2 }, { "id": "6759a890-6c2a-4bb1-aae9-9b8723b9e143", "name": "Sticky Note6", "type": "n8n-nodes-base.stickyNote", "position": [ 580, 420 ], "parameters": { "width": 668, "content": "## Loop back to fecth the refreshed Access Token\n### Note:\nYou can add further conditions and use Switch statemen tinstead of IF to validate API response based on your use case." }, "typeVersion": 1 }, { "id": "d975ce9f-2ef2-46b1-9d30-4f6e06e19b7e", "name": "Sticky Note7", "type": "n8n-nodes-base.stickyNote", "position": [ 120, -960 ], "parameters": { "width": 1413, "content": "## 1. This workflow helps you create your own Oauth 2.0 token refresh system. It helps you have better control of your oauth 2.0 auth process.\n## 2. I am using Pipedrive API here. However, you can re-use this for other similar applications. " }, "typeVersion": 1 }, { "id": "40d59a94-563d-459c-91d0-4206c2a19704", "name": "Sticky Note8", "type": "n8n-nodes-base.stickyNote", "position": [ 180, 580 ], "parameters": { "height": 248, "content": "A 3rd partyapplication posting the request to the webhook" }, "typeVersion": 1 }, { "id": "03945766-570c-47db-82c6-2c973e45106d", "name": "convert clientId and secret to base64", "type": "n8n-nodes-base.code", "position": [ 560, -560 ], "parameters": { "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nconst client_id = \"57db0bab2932f657\";\nconst client_secret = \"edfaba095e9e7ddefe2e960ce2e98345230a016d\";\n\n// Combine client_id and client_secret with a colon\nconst combinedString = client_id+\":\"+client_secret;\n\n// Encode the combined string in Base64\nconst encodedString = Buffer.from(combinedString).toString('base64');\n\n// Create the Authorization header value\nconst authorizationHeader = `Basic ${encodedString}`;\n\nreturn {\"authheader\":authorizationHeader};" }, "typeVersion": 2 }, { "id": "8ca6eb93-6994-4536-b61e-d884c8515929", "name": "Generate Refresh Token from authcode", "type": "n8n-nodes-base.httpRequest", "maxTries": 2, "position": [ 820, -560 ], "parameters": { "url": "https://oauth.pipedrive.com/oauth/token", "method": "POST", "options": { "response": { "response": { "fullResponse": true } } }, "sendBody": true, "contentType": "form-urlencoded", "sendHeaders": true, "bodyParameters": { "parameters": [ { "name": "grant_type", "value": "authorization_code" }, { "name": "code", "value": "={{$node[\"catch Auth code\"].json[\"query\"][\"code\"]}}" }, { "name": "redirect_uri", "value": "={{ $node[\"catch Auth code\"].json[\"webhookUrl\"] }}" } ] }, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "={{$node[\"convert clientId and secret to base64\"].json[\"authheader\"]}}" } ] } }, "retryOnFail": false, "typeVersion": 4, "alwaysOutputData": false }, { "id": "9c1b22e1-fd50-4c70-91cf-f4ea8cc7d3ac", "name": "Look for the related record in Supabase", "type": "n8n-nodes-base.supabase", "position": [ 1060, -540 ], "parameters": { "filters": { "conditions": [ { "keyName": "Platform", "keyValue": "Pipedrive" } ] }, "tableId": "App_tok", "operation": "get" }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1, "alwaysOutputData": true }, { "id": "53602a58-d47a-4133-b9ec-4ea421a75eea", "name": "IF rec not found", "type": "n8n-nodes-base.if", "position": [ 1260, -540 ], "parameters": { "conditions": { "number": [ { "value1": "={{ $json.values().length }}", "operation": "equal" } ] } }, "typeVersion": 1 }, { "id": "38e5d91c-1bea-4f7a-8336-98748005d02e", "name": "Update tokns in the record", "type": "n8n-nodes-base.supabase", "position": [ 1600, -460 ], "parameters": { "filters": { "conditions": [ { "keyName": "Platform", "keyValue": "Pipedrive", "condition": "eq" } ] }, "tableId": "App_tok", "fieldsUi": { "fieldValues": [ { "fieldId": "acc_token", "fieldValue": "={{ $node[\"Generate Refresh Token from authcode\"].json[\"body\"][\"access_token\"] }}" }, { "fieldId": "ref_token", "fieldValue": "={{ $node[\"Generate Refresh Token from authcode\"].json[\"body\"][\"refresh_token\"] }}" }, { "fieldId": "updated_at", "fieldValue": "={{$now.toUTC().toString()}}" } ] }, "matchType": "allFilters", "operation": "update" }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1 }, { "id": "43a2613d-7793-48c9-8934-57d9b713f5fe", "name": "Supabase- look for the record", "type": "n8n-nodes-base.supabase", "position": [ 600, -140 ], "parameters": { "filters": { "conditions": [ { "keyName": "Platform", "keyValue": "Pipedrive" }, { "keyName": "AppId", "keyValue": "={{ $node[\"Webhook\"].json[\"body\"][\"appId\"] }}" } ] }, "tableId": "App_tok", "operation": "get" }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1 }, { "id": "366bd343-419c-4a77-b2ce-e6124a6cc291", "name": "combine client id and secret", "type": "n8n-nodes-base.set", "position": [ 840, -140 ], "parameters": { "options": {}, "assignments": { "assignments": [ { "id": "4330b857-6184-4ad8-82dc-a8b806ab8077", "name": "authheader", "type": "string", "value": "57db0bab2932f657:edfaba095e9e7ddefe2e960ce2e98345230a016d" } ] } }, "typeVersion": 3.3 }, { "id": "156acb8f-3a23-40ec-b011-9db8bfa6d98b", "name": "Get Pipedrive acess token", "type": "n8n-nodes-base.httpRequest", "position": [ 1060, -140 ], "parameters": { "url": "https://oauth.pipedrive.com/oauth/token", "method": "POST", "options": {}, "sendBody": true, "contentType": "form-urlencoded", "sendHeaders": true, "bodyParameters": { "parameters": [ { "name": "grant_type", "value": "refresh_token" }, { "name": "refresh_token", "value": "={{ $node[\"Supabase- look for the record\"].json[\"ref_token\"] }}" } ] }, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "=Basic {{ $json[\"authheader\"].base64Encode() }}" } ] } }, "typeVersion": 4.2 }, { "id": "3e20309e-6d50-444c-b9e1-cf6d6982e546", "name": "IF success", "type": "n8n-nodes-base.if", "position": [ 1240, -140 ], "parameters": { "conditions": { "string": [ { "value1": "={{ Object.keys($input.first().json)[0]}}", "value2": "access_token" } ] } }, "typeVersion": 1 }, { "id": "1e991aa7-9888-404d-8f80-bb6ce0a3b777", "name": "Update thr row with new access token", "type": "n8n-nodes-base.supabase", "position": [ 1420, -280 ], "parameters": { "filters": { "conditions": [ { "keyName": "Platform", "keyValue": "Pipedrive", "condition": "eq" } ] }, "tableId": "App_tok", "fieldsUi": { "fieldValues": [ { "fieldId": "acc_token", "fieldValue": "={{ $node[\"Get Pipedrive acess token\"].json[\"access_token\"] }}" }, { "fieldId": "ref_token", "fieldValue": "={{ $node[\"Get Pipedrive acess token\"].json[\"refresh_token\"] }}" } ] }, "matchType": "allFilters", "operation": "update" }, "credentials": { "supabaseApi": { "id": "tlmP1CXY3ExzjJDs", "name": "Supabase Automation" } }, "typeVersion": 1, "alwaysOutputData": true }, { "id": "d0989bad-9176-44a2-86ce-db07a5e8a34c", "name": "Webhook", "type": "n8n-nodes-base.webhook", "position": [ 340, -140 ], "webhookId": "937a8843-a28a-400a-b473-bdc598366fa0", "parameters": { "path": "937a8843-a28a-400a-b473-bdc598366fa0", "options": {}, "httpMethod": "POST", "responseMode": "lastNode", "authentication": "basicAuth" }, "credentials": { "httpBasicAuth": { "id": "E2RYFiR9PotuglZv", "name": "PJ demo" } }, "typeVersion": 2 }, { "id": "108a2ea1-de2a-4df3-9d9f-0ce1b27a52e9", "name": "Receive request", "type": "n8n-nodes-base.webhook", "position": [ 280, 680 ], "webhookId": "47704458-bfa6-4d95-adf1-97fc78e35d8a", "parameters": { "path": "47704458-bfa6-4d95-adf1-97fc78e35d8a", "options": {}, "httpMethod": "POST", "responseMode": "responseNode", "authentication": "basicAuth" }, "credentials": { "httpBasicAuth": { "id": "E2RYFiR9PotuglZv", "name": "PJ demo" } }, "typeVersion": 1 }, { "id": "f983cfd1-52db-4839-88af-6386ec7c7256", "name": "catch Auth code", "type": "n8n-nodes-base.webhook", "position": [ 300, -560 ], "webhookId": "aae545fb-a69d-4e20-91ce-65f105d0ea2f", "parameters": { "path": "aae545fb-a69d-4e20-91ce-65f105d0ea2f", "options": {} }, "typeVersion": 1 } ], "active": false, "pinData": { "Receive request": [ { "json": { "body": { "person": { "email": "priya+solar@psw.com" } }, "query": {}, "params": {}, "headers": { "host": "http://localhost:5678", "accept": "*/*", "user-agent": "PostmanRuntime/7.39.0", "content-type": "application/json", "authorization": "Basic xxxxxxx==", "cache-control": "no-cache", "postman-token": "41b79257-xxxx-xxxx-xxxx-9e004cae4e9e", "content-length": "52", "accept-encoding": "gzip, deflate, br", "x-forwarded-for": "54.86.50.139", "x-forwarded-host": "localhost:5678", "x-forwarded-proto": "https" }, "webhookUrl": "http://localhost:5678/webhook-test/47704458-bfa6-4d95-adf1-97fc78e35d8a", "executionMode": "test" } } ] }, "settings": { "callerPolicy": "workflowsFromSameOwner", "executionOrder": "v1", "saveManualExecutions": true }, "versionId": "54499ed8-4677-400a-9e03-d0d84f8a97b5", "connections": { "Webhook": { "main": [ [ { "node": "Supabase- look for the record", "type": "main", "index": 0 } ] ] }, "IF success": { "main": [ [ { "node": "Update thr row with new access token", "type": "main", "index": 0 } ], [ { "node": "Stop and Error", "type": "main", "index": 0 } ] ] }, "Receive request": { "main": [ [ { "node": "Get Pipedrive Token", "type": "main", "index": 0 } ] ] }, "catch Auth code": { "main": [ [ { "node": "convert clientId and secret to base64", "type": "main", "index": 0 } ] ] }, "IF rec not found": { "main": [ [ { "node": "Insert", "type": "main", "index": 0 } ], [ { "node": "Update tokns in the record", "type": "main", "index": 0 } ] ] }, "Get Pipedrive Token": { "main": [ [ { "node": "Get contact from Pipedrive", "type": "main", "index": 0 } ] ] }, "Access Token Invalid": { "main": [ [ { "node": "Refresh Access Token", "type": "main", "index": 0 } ], [ { "node": "Success", "type": "main", "index": 0 } ] ] }, "Refresh Access Token": { "main": [ [ { "node": "Get Pipedrive Token", "type": "main", "index": 0 } ] ] }, "Get Pipedrive acess token": { "main": [ [ { "node": "IF success", "type": "main", "index": 0 } ] ] }, "Get contact from Pipedrive": { "main": [ [ { "node": "Access Token Invalid", "type": "main", "index": 0 } ] ] }, "combine client id and secret": { "main": [ [ { "node": "Get Pipedrive acess token", "type": "main", "index": 0 } ] ] }, "Supabase- look for the record": { "main": [ [ { "node": "combine client id and secret", "type": "main", "index": 0 } ] ] }, "Generate Refresh Token from authcode": { "main": [ [ { "node": "Look for the related record in Supabase", "type": "main", "index": 0 } ] ] }, "convert clientId and secret to base64": { "main": [ [ { "node": "Generate Refresh Token from authcode", "type": "main", "index": 0 } ] ] }, "Look for the related record in Supabase": { "main": [ [ { "node": "IF rec not found", "type": "main", "index": 0 } ] ] } } }