Forbidden error persisting

Given that you’ve systematically performed every known user-side troubleshooting step (re-authenticating credentials, explicitly sharing the calendar, revoking app access from Google, deleting and re-creating credentials, verifying all permissions were selected), and the “Forbidden” error still returns, this indicates a deeper problem.

This now requires intervention from n8n.cloud support.

They will have access to server-side logs and can investigate the specific OAuth client configuration for your n8n.cloud instance, as well as any server-side issues that might be causing the tokens to become invalid immediately.

Please reach out to n8n.cloud support and explain:

  • You are getting a persistent “Forbidden - perhaps check your credentials?” error on your Google Calendar node.
  • You have already gone through the exhaustive troubleshooting steps including:
    • Re-authenticating the credential multiple times.
    • Explicitly sharing the calendar with [email protected] with “Make changes and manage sharing” permissions.
    • Crucially, you revoked n8n.cloud’s access from your Google Account’s security settings to force a fresh connection, and successfully saw and checked all permissions on the Google consent screen during credential re-creation.
  • The error still persists immediately after these steps.

Here is a challenge for only the best :),… Subject: Persistent Google Calendar & Gmail ‘Forbidden’ / ‘Invalid Auth Grant’ Errors on n8n.cloud (Sheets Node Works!)

Hello n8n Community,

I’m a new user trying out n8n.cloud (free trial), and I’m encountering a critical issue with my Google Calendar and Gmail nodes that I’ve been unable to resolve despite extensive troubleshooting. I’m hoping someone here might have faced a similar problem or can offer insights, especially given that my Google Sheets node works perfectly.

Problem Description: My Google Calendar node repeatedly fails with the error: “Forbidden - perhaps check your credentials? You need to have writer access to this calendar.” This prevents it from creating events. More critically, I’ve also observed a broader underlying issue: “The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.” This “invalid authorization grant” error has also appeared on my Gmail node, indicating a widespread problem with Google OAuth token management for these specific services.

My Setup:

  • n8n Version: 1.98.1
  • Running n8n via: n8n.cloud
  • Google Account: All Google services (Calendar, Gmail, Sheets) are linked via [email protected].

Extensive Troubleshooting Steps Taken (Chronological Order - I’ve tried everything I can think of!):

  1. Initial Credential Re-authentication: Attempted re-authenticating existing Google Calendar and Gmail credentials in n8n multiple times.
  2. Calendar Sharing Verification: Explicitly ensured the target Google Calendar ([email protected]) was shared with [email protected] and granted “Make changes and manage sharing” permissions within Google Calendar settings. This step was confirmed saved.
  3. Expression Verification: Double-checked and corrected the Start and End expressions in the Google Calendar node to ensure they correctly parse the AI Agent’s output.
  4. Comprehensive Credential Reset (CRITICAL STEPS):
  • Revoked n8n.cloud’s access directly from my Google Account’s security settings (myaccount.google.com/security). This was done specifically to force a complete de-linking of n8n.cloud from my Google Account.
  • Deleted all existing Google Calendar and Gmail credentials from my n8n “Credentials” section.
  • Re-created a brand new Google Calendar credential (giving it a unique name like “Google Calendar - New”) and a new Gmail credential.
  • Crucially, during the re-connection process for the new credentials, I successfully reached the full Google permissions consent screen. On this screen, I made sure to select “Select all” and explicitly checked every single box related to Google Calendar access (including “View and edit events on all your calendars” and “See, edit, share, and permanently delete all the calendars you can access”) and all relevant Gmail permissions.
  • Updated the Google Calendar and Gmail nodes in my workflow to use these newly created credentials.

Key Observation (The “Smoking Gun”): Separately, I encountered and successfully resolved a similar “No columns found” error for my Google Sheets node by re-authenticating the credential. My Google Sheets node now works perfectly and appends data as expected. This strongly suggests that other Google services can connect and function correctly via n8n.cloud.

Despite all these extensive and repeated steps, the Google Calendar node consistently returns the “Forbidden” or “invalid authorization grant” error, and the Gmail node shows the “invalid authorization grant” error. The fact that I was able to successfully grant all permissions on the Google consent screen during the last credential creation attempt, yet the error persists and affects multiple Google services (while Sheets works), is highly concerning.

Suspected Root Cause: Based on similar issues observed in community forums for Google API integrations, and the nature of the “invalid authorization grant” error appearing across multiple Google services, I strongly suspect there might be an issue on the n8n.cloud infrastructure side. Specifically, it’s possible that the necessary Google Calendar API and Gmail API are not enabled or correctly configured within the Google Cloud Project that backs n8n.cloud’s OAuth client. If these APIs are not active at the project level, no amount of user-side credential re-authentication will resolve the “Forbidden” or “invalid token” errors for API calls.

Request to the Community:

  • Has anyone else on n8n.cloud (especially non-enterprise users) experienced similar “invalid authorization grant” errors with Google Calendar or Gmail, even after extensive re-authentication?
  • Are there any workarounds or specific checks I can perform from my end within n8n that I might have missed?
  • Could any n8n developers or power users confirm if the Google Calendar API and Gmail API are indeed enabled and if the correct OAuth scopes (e.g., https://www.googleapis.com/auth/calendar, https://www.googleapis.com/auth/gmail.send) are correctly configured and consented for the shared OAuth client used by n8n.cloud instances?

Thank you in advance for any assistance or insights you can provide!


Workflow JSON:

JSON{ "name": "NON HR job search", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "weeks", "triggerAtDay": [ 1 ], "triggerAtHour": 9 }, { "daysInterval": 7, "triggerAtHour": 10 } ] } }, "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [ -940, -280 ], "id": "296a5e9c-87a1-483f-8fa9-83dbb1f52a12", "name": "Schedule Trigger" }, { "parameters": { "promptType": "define", "text": "=Role and Goal: You are an AI Recruitment Analyst integrated into an automated workflow. Your primary function is to analyze job posting data from client companies. Your goal is to identify relevant roles across Human Resources, Sales, and Marketing, extract key information, draft a personalized outreach email based on a provided template, and **then execute the necessary actions using your available tools.**\n\nContext & Inputs: The workflow has just scraped job posting data and will provide you with the following information:\n\njobPostingData: The raw text of the job description to be analyzed.\ncompanyName: The name of the company that has the job opening.\ncontactFirstName: The first name of the contact at the company who will receive the email.\ncontactEmail: The email address of the contact at the company.\nsenderName: The name to be used in the email signature (e.g., \"Richard\").\n\nStep-by-Step Instructions:\n\n1. **Analyze for Relevance (TEMPORARY FOR TESTING):**\n * For the purpose of this test, **ALWAYS consider the role relevant.**\n * Set isRelevanttotrue.\n * Based on the jobPostingData, identify if it is Human Resources, Sales, or Marketing. (e.g. for \"HR Generalist\" it should be \"Human Resources\").\n * Your output for isRelevantshould betruefor all test cases.\n2. **Extract and Classify Key Information:**\n * If the role is relevant, extract the following information precisely:\n *jobTitle: The complete, official job title.\n * roleCategory: The category the role belongs to (\"Human Resources\", \"Sales\", or \"Marketing\").\n\n3. **Draft Outreach Email:**\n * Using the extracted information, draft a personalized email based on the template below.\n * Create a concise and professional subject line for the email.\n * Dynamically insert the contactFirstName, jobTitle, and companyName.\n * The closing of the email should use the provided senderName.\n\n **Email Template to Use:**\n\n ```\n Hi [contactFirstName],\n\n I see that you're looking for a [jobTitle] to join your team at [companyName].\n\n If you're inundated with resumes, don't have the time, the role is important and properly assessing the candidates is pivotal to the organization,... Let Granite help you find that next impact hire.\n\n Hope to connect,\n [senderName]\n ```\n\n4. **Execute Tool Actions (CRITICAL):**\n * **IF the role is relevant and the email has been drafted, you MUST perform the following actions using your tools:**\n * **Send Email:** Use the **'Gmail' TOOL** to send the drafted email.\n * Set the Tofield tocontactEmail.\n * Set the Subjectfield to thedraftedEmail.subject.\n * Set the Messagefield to thedraftedEmail.body.\n * **Create Follow-up Calendar Event:** Use the **'Google Calendar' TOOL** to create a follow-up event.\n * The event should be on the **'Granite Calendar'**.\n * The Summary(event title) should be \"Follow-up: [jobTitle] at [companyName]\".\n * TheStarttime should be 3 days from the current date and time (using{{ $now.plus(3, ‘days’) }}).\n * The Endtime should be 30 minutes after the start time (using{{ $now.plus(3, ‘days’).plus(30, ‘minutes’) }}).\n * **Log to Google Sheet:** Use the **'Google Sheets1' TOOL** to append a new row to the 'NON HR - email merge' spreadsheet.\n * The row should contain the following data in corresponding columns:\n * companyName\n * jobTitle\n * roleCategory\n * A status field: \"Email Sent & Follow-up Scheduled\"\n\nOutput Format: Your final output MUST be a single, valid JSON object, **after** attempting to use the tools. Do not include any text, notes, or explanations outside of the JSON structure.\n\nJSON\n\n```json\n{\n \"isRelevant\": true,\n \"contactEmail\": \"[email protected]\", // <--- ADD THIS LINE\n \"roleCategory\": \"Human Resources\",\n \"extractedJobTitle\": \"Talent Acquisition Specialist\",\n \"draftedEmail\": {\n \"subject\": \"Regarding your search for a Talent Acquisition Specialist\",\n \"body\": \"Hi Jane,...Richard\"\n },\n \"toolActions\": {\n // ... rest of your tool actions will go here\n }\n}", "options": {} }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 2, "position": [ -480, -280 ], "id": "f5be28c9-2323-43f8-a55f-7006e01cccf4", "name": "AI Agent" }, { "parameters": { "model": { "__rl": true, "mode": "list", "value": "gpt-4.1-mini" }, "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.2, "position": [ -920, -40 ], "id": "e8e352de-02b8-4ce4-b41f-2a1835b8aca5", "name": "OpenAI Chat Model", "credentials": { "openAiApi": { "id": "kBUlnGJpATL7dAab", "name": "OpenAi account 2" } } }, { "parameters": { "sessionIdType": "customKey", "sessionKey": "={{ $execution.id }}" }, "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow", "typeVersion": 1.3, "position": [ -760, -20 ], "id": "35ff8cf4-0e5a-44d4-a94d-35c08d24d5e1", "name": "Simple Memory" }, { "parameters": { "options": {} }, "type": "@n8n/n8n-nodes-langchain.memoryManager", "typeVersion": 1.1, "position": [ -840, 120 ], "id": "946b8697-a741-4705-b55a-9a69bc476178", "name": "Chat Memory Manager" }, { "parameters": { "assignments": { "assignments": [ { "id": "a7b14ada-2252-4459-83a6-ae8ede3de456", "name": "contactFirstName", "value": "Jane", "type": "string" }, { "id": "8deb440b-4657-455f-ba3b-e16d6dc418b1", "name": "contactEmail", "value": "[email protected]", "type": "string" }, { "id": "7121f378-43da-4540-b3c2-86e1a8b08fa1", "name": "companyName", "value": "Acme Corp", "type": "string" }, { "id": "d2387f8a-2f6a-4ec4-b4d8-3f38c3de4480", "name": "jobPostingData", "value": "Our growing tech company is seeking an experienced HR Generalist to manage daily HR operations, including talent acquisition, employee relations, and compliance. This role will involve significant interaction with new hires and existing staff. Responsibilities include onboarding, benefits administration, and supporting HR initiatives. Requires 3+ years in a similar HR role.", "type": "string" }, { "id": "00e31461-991b-4ba2-a2d3-fecbb0390fae", "name": "senderName", "value": "Richard", "type": "string" } ] }, "includeOtherFields": true, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ -660, -360 ], "id": "5601eba5-8b14-4605-8f2d-b67e0aecdf25", "name": "Edit Fields" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "loose", "version": 2 }, "conditions": [ { "id": "79ea3681-9e44-4dd7-9a02-37b2545ec9a5", "leftValue": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true } }, { "id": "7ebcf292-262b-447f-a631-a085c059dc3d", "leftValue": "", "rightValue": "", "operator": { "type": "string", "operation": "equals", "name": "filter.operator.equals" } } ], "combinator": "and" }, "looseTypeValidation": true, "options": {} }, "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ -200, -100 ], "id": "fd613ceb-3187-4bd4-bc9d-b57496ccc8f9", "name": "If" }, { "parameters": { "sendTo": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions.Gmail.To }}", "subject": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions.Gmail.Subject }}", "emailType": "text", "message": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions.Gmail.Message }}", "options": {} }, "type": "n8n-nodes-base.gmail", "typeVersion": 2.1, "position": [ -460, -60 ], "id": "59cdc0ae-8775-48e3-a367-1ae02bcffa27", "name": "Gmail", "webhookId": "de6e3467-d94d-4d1e-8733-c2ae25418a03", "credentials": { "gmailOAuth2": { "id": "KBckdwSXs7vlMVuE", "name": "Gmail account" } } }, { "parameters": { "calendar": { "__rl": true, "value": "[email protected]", "mode": "list", "cachedResultName": "[email protected]" }, "start": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Calendar\"].Start }}", "end": "={{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Calendar\"].End }}", "additionalFields": {} }, "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1.3, "position": [ -220, 120 ], "id": "8459ceed-f5e4-4bdf-9e4c-c8ed3339aae0", "name": "Google Calendar", "credentials": { "googleCalendarOAuth2Api": { "id": "LKNpjMQaBhfa0bjr", "name": "Granite Calendar" } } }, { "parameters": { "operation": "append", "documentId": { "__rl": true, "value": "18mpyepI-HbJk1G8qTbinLlBsuNbG2xKD2Whbh9-0nKg", "mode": "list", "cachedResultName": "NON HR - email merge", "cachedResultUrl": "[https://docs.google.com/spreadsheets/d/18mpyepI-HbJk1G8qTbinLlBsuNbG2xKD2Whbh9-0nKg/edit?usp=drivesdk](https://docs.google.com/spreadsheets/d/18mpyepI-HbJk1G8qTbinLlBsuNbG2xKD2Whbh9-0nKg/edit?usp=drivesdk)" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "Sheet1", "cachedResultUrl": "[https://docs.google.com/spreadsheets/d/18mpyepI-HbJk1G8qTbinLlBsuNbG2xKD2Whbh9-0nKg/edit#gid=0](https://docs.google.com/spreadsheets/d/18mpyepI-HbJk1G8qTbinLlBsuNbG2xKD2Whbh9-0nKg/edit#gid=0)" }, "columns": { "mappingMode": "defineBelow", "value": { "Company Name": "{{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Sheets1\"].RowData[0] }}", "Email Sent": "{{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Sheets1\"].RowData[3] }}", "Email": "{{ $node[\"Edit Fields\"].json.contactEmail }}", "First Name": "{{ $node[\"Edit Fields\"].json.contactFirstName }}", "Role Category": "{{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Sheets1\"].RowData[2] }}", "Job Title": "{{ JSON.parse($json.output.substring(7, $json.output.length - 3)).toolActions[\"Google Sheets1\"].RowData[1] }}" }, "matchingColumns": [], "schema": [ { "id": "First Name", "displayName": "First Name", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "Email", "displayName": "Email", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "Company Name", "displayName": "Company Name", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "Job Title", "displayName": "Job Title", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "Role Category", "displayName": "Role Category", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false }, { "id": "Email Sent", "displayName": "Email Sent", "required": false, "defaultMatch": false, "display": true, "type": "string", "canBeUsedToMatch": true, "removed": false } ], "attemptToConvertTypes": false, "convertFieldsToString": false }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.6, "position": [ -60, 160 ], "id": "f4b7806b-1cf7-40f7-b11b-dfb15eef5530", "name": "Google Sheets", "credentials": { "googleSheetsOAuth2Api": { "id": "qj0ZW1RgiLKX2ILj", "name": "Google Sheets account 2" } } } ], "pinData": {}, "connections": { "Schedule Trigger": { "main": [ [ { "node": "AI Agent", "type": "main", "index": 0 }, { "node": "Edit Fields", "type": "main", "index": 0 } ] ] }, "OpenAI Chat Model": { "ai_languageModel": [ [ { "node": "AI Agent", "type": "ai_languageModel", "index": 0 } ] ] }, "Simple Memory": { "ai_memory": [ [ { "node": "AI Agent", "type": "ai_memory", "index": 0 }, { "node": "Chat Memory Manager", "type": "ai_memory", "index": 0 } ] ] }, "AI Agent": { "main": [ [ { "node": "If", "type": "main", "index": 0 } ] ] }, "If": { "main": [ [ { "node": "Gmail", "type": "main", "index": 0 } ] ] }, "Gmail": { "main": [ [ { "node": "Google Calendar", "type": "main", "index": 0 } ] ] }, "Google Calendar": { "main": [ [ { "node": "Google Sheets", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1" }, "versionId": "63ba0104-297d-42ca-bf6b-ededd4715a68", "meta": { "templateCredsSetupCompleted": true, "instanceId": "68418698814890ffb2a4e977a3654097c143f187ca8ece1d96eca4634100a58a" }, "id": "xymLkGfF14INwRkR", "tags": [] }

Debug Information:

`# Debug info

core

  • n8nVersion: 1.98.1
  • platform: docker (cloud)
  • nodeJsVersion: 22.16.0
  • database: sqlite
  • executionMode: regular
  • concurrency: 5
  • license: community
  • consumerId: 00000000-0000-0000-0000-000000000000

storage

  • success: all
  • error: all
  • progress: false
  • manual: true
  • binaryMode: filesystem

pruning

  • enabled: true
  • maxAge: 168 hours
  • maxCount: 2500 executions

client

  • userAgent: mozilla/5.0 (macintosh; intel mac os x 10_15_7) applewebkit/537.36 (khtml, like gecko) chrome/137.0.0.0 safari/537.36
  • isTouchDevice: false

Generated at: 2025-06-22T11:20:02.421Z`