Generic Oauth2 未能刷新

大家好,

我在整合 Jobber 的 API 時遇到麻煩。我已經初步完成身份驗證,也有一些可運作的工作流程,但當 access_token 過期時,一切在 1 小時後就會中斷。

根據我的測試,Jobber 不需要特殊的作用域就能返回重新整理令牌,但出於某種原因,它要麼沒有被返回/儲存,要麼 n8n 無法正確處理。

有任何建議嗎?

以下是我從 GitHub 上提出的問題中貼上的疑難排解資訊

以下是他們的文件 - https://developer.getjobber.com/docs/building_your_app/app_authorization/

我能夠初步授權,但在 1 小時過期後,我收到以下錯誤

輸出
1 項
授權失敗 - 請檢查您的憑證
不支援的內容類型:text/plain; charset=utf-8
錯誤詳情

來自 HTTP 請求
錯誤代碼

401

完整訊息

不支援的內容類型:text/plain; charset=utf-8
請求

{ “hidden”: “{\n “query”: “{ quotes(first: 10, filter: { status: converted}) { nodes { id quoteNumber notes(first: 5) { nodes { … on QuoteNote { message } } } } } }”\n}”, “headers”: { “content-type”: “application/json”, “x-jobber-graphql-version”: “2025-04-16”, “accept”: “application/json,text/html,application/xhtml+xml,application/xml,text/;q=0.9, image/;q=0.8, /;q=0.7”, “Authorization”: “hidden” }, “method”: “POST”, “uri”: “https://api.getjobber.com/api/graphql”, “gzip”: true, “rejectUnauthorized”: true, “followRedirect”: true, “resolveWithFullResponse”: true, “sendCredentialsOnCrossOriginRedirect”: false, “followAllRedirects”: true, “timeout”: 300000, “encoding”: null, “json”: false, “useStream”: true }
其他資訊
項目索引

0

節點類型

n8n-nodes-base.httpRequest

節點版本

4.4 (最新)

n8n 版本

2.20.6 (自行代管)

時間

5/12/2026, 9:52:03 AM

堆疊追蹤

NodeApiError: Authorization failed - please check your credentials at ExecuteContext.execute (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-nodes-base@file+packages+nodes-base_@aws-sdkaws-sdkaws-sdkaws-sdk+credential-providers@3.808.0_asn1.js@5_8da18263ca0574b0db58d4fefd8173ce/node_modules/n8n-nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts:825:16) at WorkflowExecute.executeNode (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+package@opent@openlemetry+core_@open@opentelemetrye@opentelemetryemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_2c2e1f47b69b34bef6f634a13cbf61d9/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:1048:9) at WorkflowExecute.runNode (/usr/local/lib/@opentelemetrynpmode_modules/n8n/node_modules/.@opentelemet@opentelemetryynpm/n8n-co@opentelemetry@opentelemetry@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_2c2e1f47b69b34bef6f634a13cbf61d9/node_modules/n8n-core/@opentelemetryodulesrc/ex@opentelemetryode_modulescution-engine/workflow-execute.ts:1@opentelemetry39:11) at /@opentelemetrysr/local/lib/node_@opentelemetryodules/n8n/@opentelemetryode_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@@opentelemetry7.9.0_@opentelemetry+exporter-trace-otlp_2c2e1f47b69b34bef6f634a13cbf61d9/node_modules/n8n-core/s@opentelemetryc/execution@opentelemetryengine/workflow-execute.ts:1687:@opentelemetry7 at /usr/l@opentelemetrycal/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_2c2e1f47b69b34bef6f634a13cbf61d9/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:2339:11
根據我的理解,401 回應應該觸發令牌重新整理,但這似乎沒有發生。重新觸發工作流程也無法幫助。

如果我進入憑證並點擊「重新連接」,這將允許後續工作流程執行在一小時內運作。

重現步驟
使用針對輪換重新整理令牌的提供者的 authorization_code 設定通用 OAuth2 憑證。
成功執行工作流程。
等待存取令牌過期。
觀察重新整理循環;在後續循環後,授權失敗,需要重新連接。
預期行為
n8n 應該保留並使用令牌重新整理回應中的最新輪換 refresh_token。
工作流程應該繼續進行,無需手動重新連接。

偵錯資訊
偵錯資訊
core
n8nVersion: 2.20.6
platform: docker (self-hosted)
nodeJsVersion: 24.14.1
nodeEnv: production
database: sqlite
executionMode: regular
concurrency: -1
license: enterprise (production)
consumerId: 268c9581-f4d9-44ed-a7be-25c5c834d114
storage
success: all
error: all
progress: false
manual: true
binaryMode: filesystem
pruning
enabled: true
maxAge: 336 hours
maxCount: 10000 executions
client
userAgent: mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/148.0.0.0 safari/537.36
isTouchDevice: false
cluster
instanceCount: 1
versions: 2.20.6
instances:
instanceKey: 0cffc1ac-43d6-4469-85cf-116816732522, hostId: main-dec161f067e6, instanceType: main, instanceRole: leader, version: 2.20.6
checks:
check: hostid-clash, status: succeeded, warnings: -
check: lifecycle, status: succeeded, warnings: -
check: split-brain, status: succeeded, warnings: -
check: version-mismatch, status: succeeded, warnings: -
Generated at: 2026-05-12T17:00:18.159Z

作業系統
Ubuntu 22.04 LTS

n8n 版本
2.20.6

Node.js 版本
無論映像中是什麼:docker.n8n.io/n8nio/n8n

資料庫
SQLite (預設)

執行模式
main (預設)

代管
自行代管

歡迎 @oxidation0917 加入我們的社群!我是 Jay,是一名 n8n 認證創作者。

這是 Generic OAuth2 的一個已知問題 - 在某些情況下,重新整理令牌(refresh token)沒有被正確儲存或使用。等待修復期間的實際解決方案:在 Generic OAuth2 認證中,確保「Authentication」設定為「Body」(而非 Header),前提是 Jobber 支援的話,並檢查令牌 URL 是否正確,以及是否在請求本體中包含任何必需的用戶端認證。如果 Jobber 的存取令牌有效期很短(1 小時),你也可以建立手動重新整理流程:設定一個定時工作流程,每 55 分鐘執行一次,透過 HTTP 請求呼叫 Jobber 的令牌端點並設定 grant_type: refresh_token,然後透過 n8n REST API 更新認證。這樣可以在修復該問題前保持正常運作。

@nguyenthieutoan 非常感謝你的查看。

我目前在驗證設定中使用 Body,因為那是唯一可行的方式。當你說檢查 Jobber 是否在 body 中包含必要的憑證時,你是指檢查 curl 的 body 嗎?

我曾考慮過你建議的做法,使用 cron 觸發器,但在我的腦子裡以及根據文件,我無法完全理解這個方法。有沒有辦法在 http 請求中訪問存儲的憑證(特別是 refresh_token)?我能理解透過 API 更新憑證的部分(我還需要弄清楚結構),但由於請求需要 refresh_token,我在如何訪問它的問題上卡住了。

@oxidation0917,很樂意為你進一步說明。

  1. 關於「body 中的憑證」
    當我提到檢查 Jobber 是否在 body 中包含所需的憑證時,我的意思是:將你從 n8n 發送的內容與 Jobber 文件中的工作 curl 範例或你自己的測試進行比較。例如,在典型的 OAuth2 重新整理呼叫中,body 通常需要以下欄位:
  • grant_type=refresh_token

  • refresh_token=<your_refresh_token>

  • client_id=<your_client_id>

  • client_secret=<your_client_secret>

如果你的 curl 範例有效但 n8n HTTP Request 節點失敗,你可以將 curl 中完全相同的 body 和標題鏡像到該節點中。

  1. 存取已儲存的 refresh_token
    不幸的是,由於目前 Generic OAuth2 的錯誤,n8n 在一般節點中沒有以簡單的方式公開儲存的 refresh_token。這正是自動重新整理中斷的原因。因此,與其試圖在執行時從憑證中「讀取」重新整理令牌,常見的解決方法是:
  • refresh_token 儲存在你可以控制的位置,例如:

    • n8n 變數(環境變數),或

    • 單獨的資料庫/表格,或

    • 簡單的資料存儲,如 PostgreSQL/Firestore/Notion,取決於你的堆疊。

  • 然後你的排程工作流程可以:

    • 讀取已儲存的 refresh_token

    • 使用 grant_type=refresh_token 呼叫 Jobber 的令牌端點

    • 透過 REST API 更新 n8n 中的存取令牌

  1. 手動重新整理流程的草圖
    非常粗略地說,工作流程會像這樣:
  • Cron 節點:每 55 分鐘執行一次

  • (可選)從你的儲存空間中取得最新儲存 refresh_token 的節點

  • HTTP Request 節點:

    • 方法:POST

    • URL:Jobber 令牌 URL

    • 驗證:無(因為你在 body 中發送所有內容)

    • Body:grant_type=refresh_tokenrefresh_token=...client_idclient_secret 等。

  • HTTP Request 節點(n8n API):

    • 方法:PATCH

    • URL:https://<your-n8n-url>/rest/credentials/<credential-id>

    • 驗證:使用你的 n8n API 驗證

    • Body:更新 accessToken(以及如果 Jobber 傳回新的,可選地更新重新整理令牌)

如果你想要,我可以為 Jobber 令牌請求和 n8n 憑證更新承載準備一個具體的 JSON 範例,這樣你就可以直接將它們插入你的執行個體中。

看起來 n8n 在初始 OAuth 流程後可能沒有儲存 refresh_token。我建議你檢查來自 Jobber 的完整 token 回應,確認 refresh token 是否真的被返回並持久化。有時提供者只會在第一次授權請求時返回它。

你也可以嘗試在 OAuth 配置中強制執行離線存取 / 同意參數。既然你已經在 GitHub 上開啟了 issue,分享原始 token 回應(移除機密資訊後)應該能幫助快速縮小問題範圍。

@nguyenthieutoan 謝謝!這太棒了。我正在逐步記錄過程,但在通過 API 更新時遇到了問題。

最初我試過:

{
  "data": {
    "oauthTokenData": {
      "access_token": "access_token",
      "refresh_token": "refresh_token"
    }
  }
}

但我得到

{
  "message": "request.body.data does not match allOf schema [subschema 0] with 12 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"grantType\",request.body.data does not match allOf schema [subschema 1] with 1 error[s]:,request.body.data requires property \"accessTokenUrl\",request.body.data does not match allOf schema [subschema 2] with 1 error[s]:,request.body.data requires property \"clientId\",request.body.data does not match allOf schema [subschema 3] with 1 error[s]:,request.body.data requires property \"clientSecret\",request.body.data does not match allOf schema [subschema 4] with 1 error[s]:,request.body.data requires property \"scope\",request.body.data does not match allOf schema [subschema 5] with 1 error[s]:,request.body.data requires property \"authentication\",request.body.data does not match allOf schema [subschema 1] with 2 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"serverUrl\",request.body.data does not match allOf schema [subschema 2] with 4 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"authUrl\",request.body.data does not match allOf schema [subschema 1] with 1 error[s]:,request.body.data requires property \"authQueryParameters\",request.body.data does not match allOf schema [subschema 3] with 4 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"sendAdditionalBodyProperties\",request.body.data does not match allOf schema [subschema 1] with 1 error[s]:,request.body.data requires property \"additionalBodyProperties\",request.body.data does not match allOf schema [subschema 4] with 2 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"jwksUriNotice\""
}

我嘗試提供它,經過幾次與 Claude 的反覆調整後,最終得到了這個:

{
  "data": {
    "grantType": "authorizationCode",
    "clientId": "clientId",
    "clientSecret": "clientSecret",
    "accessTokenUrl": "https://api.getjobber.com/api/oauth/token",
    "authUrl": "https://api.getjobber.com/api/oauth/authorize",
    "serverUrl": "{{MY N8N HOST?}}"
    "authQueryParameters": "",
    "scope": "",
    "authentication": "body",
    "jweEnabled": false,
    "oauthTokenData": {
      "access_token": "access_token",
      "refresh_token": "refresh_token",
      "token_type": "Bearer"
    }
  }
}

它似乎通過了 schema 檢查,但現在我得到了 500 錯誤。我不知道 serverURL 中應該放什麼,所以我輸入了我的 n8n 主機。

Code	Details
500
Undocumented
Error: Internal Server Error

Response body
Download

<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Internal Server Error</pre>
</body>
</html>

這是我從資料庫中獲取的憑證結構,其中沒有 API 要求的任何額外參數。@David_Warner,看起來 n8n 正在儲存 refresh_token

{
    "authUrl": "https://api.getjobber.com/api/oauth/authorize",
    "accessTokenUrl": "https://api.getjobber.com/api/oauth/token",
    "clientId": "clientId",
    "clientSecret": "clientSecret",
    "scope": "offline_access",
    "authentication": "body",
    "oauthTokenData": {
        "access_token": "access_token",
        "refresh_token": "refresh_token",
        "token_type": "Bearer"
    }
}

稍等一下。我在調整 Request_Body 後,成功讓 API 更新生效了。我很快就會分享詳細內容。

編輯 - 以下是我目前整理的文檔。

非常感謝 @nguyenthieutoan 為我指點了正確的方向。我已經取得了很大的進展。

希望能讓其他人(以及我自己)在未來更容易地完成此操作,我再次進行了所有身份驗證步驟,並邊進行邊進行了文檔記錄。

初始身份驗證 / 測試

  1. 授權 URL - 在使用 Jobber 進行身份驗證的瀏覽器中輸入。您將被重定向到的 URL 包含授權代碼和狀態作為確認。
https://api.getjobber.com/api/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https:/YOUR_HOST/rest/oauth2-credential/callback&state=abc123

我收到的回應:

https://n8n.lab.atreehuman.com/rest/oauth2-credential/callback?code=CODE&state=abc123
  1. 使用授權代碼的 Curl - 使用之前 URL 中的 code 調整此 CURL
curl -X POST https://api.getjobber.com/api/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=CODE&redirect_uri=YOUR_HOST/rest/oauth2-credential/callback"

回應:

{"access_token":"ACCESS_TOKEN","refresh_token":"REFRESH_TOKEN"}%

現在您已通過身份驗證,您有 1 小時的時間在 access_token 過期之前進行刷新。之後,您的 refresh_token 應該可以工作(無限期,直到輪換為止?)。默認情況下,Jobber API 在每次刷新 access_token 時會輪換 refresh_token。您必須將 refresh_token 存儲在可從工作流程訪問的地方。

  1. 測試 API 授權:
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" "https://api.getjobber.com/api/graphql"

授權時的回應:

{"message":"An API version must be specified"}%

更新 n8n 憑證

  1. 在 Settings > n8n API 下創建 API 密鑰,範圍為 credential:listcredential_updatecredential:read。將彈出窗口中顯示的密鑰保存到您的剪貼板和安全位置。稍後在創建刷新的 cron 工作流程時,您會需要它。

  2. 打開 API Playground 並使用您的 API 密鑰進行授權。我發現在授權後必須刷新頁面才能使授權生效。

  3. 向下滾動到 GET /credentials,點擊並「試試看」

  4. 在回應數據中找到您的 Jobber 憑證,並將其 id 保存到您的記事本和剪貼板

  5. 向下看,找到 PATCH /credentials/id,點擊「試試看」並粘貼您的 id

  6. 在「Request Body」中粘貼以下內容並使用您的數據進行更新。(refresh_token 不一定需要在此,因為 n8n 沒有使用它)

{
    "data": {
        "grantType": "authorizationCode",
        "serverUrl": "",
        "jweEnabled": false,
        "clientId": "CLIENT_ID",
        "clientSecret": "CLIENT_SECRET",
        "accessTokenUrl": "https://api.getjobber.com/api/oauth/token",
        "authUrl": "https://api.getjobber.com/api/oauth/authorize",
        "scope": "",
        "authentication": "body",
        "authQueryParameters": "",
        "oauthTokenData": {
            "access_token": "ACCESS_TOKEN",
            "refresh_token": "REFRESH_TOKEN"
        }
    }
}

您應該會收到代碼 200 和回應正文:

{
    "id": "ID",
    "name": "Jobber",
    "type": "oAuth2Api",
    "isManaged": false,
    "isGlobal": false,
    "isResolvable": false,
    "resolvableAllowFallback": false,
    "resolverId": null,
    "createdAt": "2026-05-09T17:53:07.738Z",
    "updatedAt": "2026-05-16T19:27:53.231Z"
}

現在剩下的就是將您的 refresh_token 移動到一個安全的地方,該地方可以從工作流程訪問,然後構建一個刷新令牌並更新 API 的工作流程。

刷新您的 access_token

curl -X POST https://api.getjobber.com/api/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN"

回應:

{"access_token":"ACCESS_TOKEN","refresh_token":"REFRESH_TOKEN"}%

只需使用上述 API 更新您的憑證,您應該就會設置好。現在只需將所有這些變成一個工作流程並應用臨時修補程序!

So, I’m still hoping to get this issue resolved, but for now we can workaround it.

Here’s a workflow I came up with. You’d have to set up a Postgres database / credentials and point those nodes at it as well as set an error reporting workflow, or disable that flag.

I don’t really like storing the credentials in the database, but currently it’s the most practical approach without a self-hosted enterprise license. Any suggestions otherwise that are more secure?

I’m open to any suggestions on the workflow too. Thanks all!

編輯 - 取消標記為解決方案。

嗯,這算是一種解決方案。它讓身份驗證持續更久。也許現在能維持一天,但似乎 n8n 的確在刷新令牌,只是按照它自己的時間表。這最終導致臨時修補失效

這也有可能影響 GitHub OAuth2 API 認證,而不只是通用 OAuth2 認證?我正在使用 GitHub OAuth2 認證以及 GitHub 節點來擷取資訊。我最近一直收到 401 錯誤:
{ "message": "Bad credentials", "documentation_url": "https://docs.github.com/rest", "status": "401" }

我可以手動點擊認證頁面上的「重新連接」按鈕來解決此問題。但這個因應方案只能維持幾小時。

我遇到相同的問題,MCP OAuth2 API 節點無法更新令牌。有任何修復方面的更新嗎?

有兩個容易被忽略的檢查項目:首先,確保在通用 OAuth2 認證憑證中的「Refresh URL」欄位明確設定為你的提供者的 token 端點 - n8n 不會從「Access Token URL」推斷它,儘管它們通常是相同的。其次,檢查你的初始授權請求是否包含 access_type=offline(或對於 Google 型提供者使用 prompt=consent)- 沒有它,許多提供者根本不會發出重新整理 token,所以當存取 token 過期時,n8n 就沒有可用的東西。你可以在認證憑證設定中的「Auth URI Query Parameters」下新增這些參數。

感謝 @nguyenthieutoan 的回覆。是的,我之前都試過了,但大約1小時後就不會刷新了。

關於URL,是的,我填入了驗證URL和存取權杖URL,

還有其他故障排除的方法嗎?

謝謝,

對於 Google 具體而言,refresh token 只會在第一次授權時發出 - 就在最初的授權時。如果您在「Auth URI Query Parameters」欄位中未加入 access_type=offlineprompt=consent 就進行授權,Google 不會傳回 refresh token,再多的網址調整也無法解決。試試看:在您的憑證中,在 Auth URI Query Parameters 下方新增 access_type=offlineprompt=consent,然後撤銷並從零開始重新授權該憑證。這樣 Google 就應該會發出一份全新的 refresh token。

感謝,看起來那個有效了。

不知道如何同時發送兩者,但很簡單,"access_type=offline&prompt=consent"