{"record":{"id":"d2936362de877c29","repo":"n8n-io/n8n","slug":"oauth-access-token-expired-and-no-refresh-token-is","errorCode":null,"errorMessage":"OAuth access token expired and no refresh token is available. Please reconnect the credentials.","messagePattern":"OAuth access token expired and no refresh token is available\\. Please reconnect the credentials\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/client-oauth2/src/client-oauth2-token.ts","lineNumber":79,"sourceCode":"\t\t\t// Attempt to avoid storing the url in proxies, since the access token\n\t\t\t// is exposed in the query parameters.\n\t\t\trequestObject.headers.Pragma = 'no-store';\n\t\t\trequestObject.headers['Cache-Control'] = 'no-store';\n\t\t}\n\n\t\treturn requestObject;\n\t}\n\n\t/**\n\t * Refresh a user access token with the refresh token.\n\t * As in RFC 6749 Section 6: https://www.rfc-editor.org/rfc/rfc6749.html#section-6\n\t * Supports PKCE flows (RFC 7636) for public clients without client secret\n\t */\n\tasync refresh(opts?: ClientOAuth2Options): Promise<ClientOAuth2Token> {\n\t\tconst options = { ...this.client.options, ...opts };\n\n\t\tif (!this.refreshToken) {\n\t\t\tthrow new Error(\n\t\t\t\t'OAuth access token expired and no refresh token is available. Please reconnect the credentials.',\n\t\t\t);\n\t\t}\n\n\t\tconst { clientId, clientSecret } = options;\n\t\tconst headers = { ...DEFAULT_HEADERS };\n\t\tconst body: Record<string, string> = {\n\t\t\trefresh_token: this.refreshToken,\n\t\t\tgrant_type: 'refresh_token',\n\t\t\t...(options.resource ? { resource: options.resource } : {}),\n\t\t};\n\n\t\tif (options.clientCredentialType === 'certificate') {\n\t\t\texpects(options, 'clientCertificate');\n\t\t\tbody.client_id = clientId;\n\t\t\tbody.client_assertion_type = CLIENT_ASSERTION_TYPE;\n\t\t\tbody.client_assertion = buildClientAssertion({\n\t\t\t\tclientId,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/client-oauth2/src/client-oauth2-token.ts#L61-L97","documentation":"Generic Error thrown by ClientOAuth2Token.refresh when this.refreshToken is falsy at the start of the refresh flow (RFC 6749 §6). Without a refresh token the client cannot obtain a new access token, so the user must re-authenticate. The message is user-facing and instructs reconnection.","triggerScenarios":"A credential's access token has expired (token.expired() true), the n8n runtime calls token.refresh(), but the stored credential has no refresh_token. Common when the original grant did not include one.","commonSituations":"OAuth2 flow was configured without the offline_access / refresh scope; the provider's grant type does not issue refresh tokens (e.g. client_credentials, some implicit flows, resource owner password with certain providers); the refresh token was already consumed and rotated out; the credential was imported without its refresh token.","solutions":["Reconnect the OAuth2 credential in n8n so a fresh authorization code (with refresh scope) is exchanged.","Ensure the OAuth2 credential config requests offline_access (Microsoft/Azure) or the provider's refresh scope.","Switch to an authorization grant that issues refresh tokens (authorization_code with offline_access).","If using client_credentials, do not rely on refresh — fetch a new token directly."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before refreshing, check whether a refresh token exists\nif (!credential.oauthRefreshToken) {\n  throw new Error('Reconnect the credential — no refresh token available');\n}","typeGuard":"const hasRefreshToken = (token: { refreshToken?: string }): boolean => !!token.refreshToken;","tryCatchPattern":"try {\n  return await oauthToken.refresh();\n} catch (e) {\n  if (e instanceof Error && /no refresh token is available/.test(e.message)) {\n    // mark credential as needing reconnection in the UI\n  }\n  throw e;\n}","preventionTips":["Always request offline_access (Microsoft) or the provider's refresh scope during authorization.","Use authorization_code grant for long-lived credentials that need refresh.","Do not store credentials without their refresh_token; import complete token sets."],"tags":["oauth2","auth","refresh-token","credentials","client-oauth2"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}