🔄 [GitHub Issue #17450] OAuth2 Client Credentials in n8n does not refresh token after expiry (403 error)

Hi community! :waving_hand:

I wanted to bring attention to an existing GitHub issue that affects OAuth2 integrations, particularly with APIs like Avito that return 403 instead of 401 when tokens expire.

:clipboard: Background:

:police_car_light: The Problem Affects Both Avito Authorization Methods:

Avito API supports two OAuth2 authorization methods, and both encounter the same issue:

1. client_credentials flow:

  • No refresh_token provided (by OAuth2 design)
  • Token expires after 24 hours
  • Returns 403 on expiry → n8n doesn’t refresh

2. authorization_code flow:

  • refresh_token IS provided in the response
  • Token expires after 24 hours
  • Returns 403 on expiry → n8n STILL doesn’t refresh the token
  • This proves the issue is specifically with 403 response handling, not missing refresh tokens

:bar_chart: Technical Details from My Testing:

Avito API Response Examples:

json

// 1. client_credentials (no refresh_token)
{
  "access_token": "kChqt9ewQNAcwgbHp4yFd5",
  "expires_in": 86400,
  "token_type": "Bearer"
}

// 2. authorization_code (WITH refresh_token)
{
  "access_token": "kChqt9ewQNAcwgbHp4yFd5",
  "expires_in": 86400,
  "refresh_token": "QNAcwgbHQNAcwgbHkChqt9ewQNAcwgbHp4yFd5",
  "scope": "messenger:read,messenger:write",
  "token_type": "Bearer"
}

After 24h expiry, BOTH methods return:

json

{
  "result": {
    "status": false,
    "message": "invalid access token"
  }
}
// Status Code: 403 (not 401!)

:magnifying_glass_tilted_left: Root Cause Analysis: The issue occurs regardless of whether refresh_token is available. Even in authorization_code flow where refresh token exists, n8n fails to refresh because:

  • n8n only triggers token refresh on 401 responses
  • Avito returns 403 (following their API specification)
  • n8n ignores the expires_in timing completely

Current n8n Limitation:

  • Only triggers token refresh on 401 responses
  • Doesn’t use 403 as refresh trigger
  • Ignores expires_in parameter for proactive refresh

:wrench: Current Workaround (Not Ideal): Right now, I have to:

  1. Manually fetch tokens outside of n8n credentials system
  2. Store tokens directly in workflow variables
  3. Manually handle expiration logic for BOTH authorization methods
  4. This creates security concerns and maintenance overhead

:light_bulb: What I’d Love to See:

  1. Support for 403 as a trigger for token refresh (configurable)
  • This would fix the issue for BOTH Avito authorization methods
  1. Flexible token refresh strategies in custom OAuth2 nodes:
  • Reactive refresh (current behavior): Token refreshes only after error occurs
  • Proactive refresh (optional): User-configurable time window for token renewal (e.g., refresh 60 minutes before expiration)
  • This would give users control over when tokens are refreshed, if technically feasible within n8n’s core
  1. Custom token refresh logic for client_credentials flows:
  • In non-standard OAuth2 implementations, APIs might use different field names for token expiration
  • Allow specifying custom field mapping (e.g., mapping a custom expires_in field or other expiration indicators)
  • This would handle edge cases where APIs don’t follow exact OAuth2 specifications

:handshake: Community Question: Has anyone else encountered similar issues with APIs that return 403 on token expiry? How are you currently handling OAuth2 integrations with such APIs?

The fact that this affects both Avito authorization methods (even when refresh_token is available) shows this is a broader n8n OAuth2 handling issue that could affect other APIs with similar behavior.

GitHub Issue Link: OAuth2 Client Credentials in n8n Cloud does not refresh token after expiry (403 error) · Issue #17450 · n8n-io/n8n · GitHub

Would appreciate any thoughts, similar experiences, or potential workarounds from the community! :folded_hands: