APIs that use OAuth2 require periodic token refresh.
APIs that use OAuth2 require periodic token refresh. Native n8n nodes handle this automatically, but when using the HTTP Request node with OAuth2 APIs, you need to manage token lifecycle yourself. The pattern: store the refresh token in n8n credentials, detect 401 responses, call the token endpoint to get a new access token, retry the original request, and update the stored credentials.
Real-world example: You are integrating with a custom OAuth2 API. The access token expires every hour and needs to be refreshed using the refresh token.
// This Code node wraps any API call with automatic token refresh.
// Place it before nodes that call OAuth2-protected APIs.
const tokenUrl = "https://auth.example.com/oauth2/token";
const clientId = "your-client-id";
const clientSecret = "your-client-secret";
// Retrieve the current tokens from a static node or
// workflow static data
const staticData = $getWorkflowStaticData("global");
let accessToken = staticData.accessToken;
let refreshToken = staticData.refreshToken;
// Check if token needs refresh (stored expiry time)
const now = Date.now();
const expiresAt = staticData.expiresAt || 0;
if (now >= expiresAt - 60000) {
// Token expired or will expire within 60 seconds -- refresh it
const response = await this.helpers.httpRequest({
method: "POST",
url: tokenUrl,
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret,
}).toString(),
});
accessToken = response.access_token;
refreshToken = response.refresh_token || refreshToken;
// Store updated tokens in workflow static data
staticData.accessToken = accessToken;
staticData.refreshToken = refreshToken;
staticData.expiresAt = now + (response.expires_in * 1000);
}
// Pass the valid access token to the next node
return [{
json: {
accessToken: accessToken,
...$input.first().json
}
}];
```text
```text title="Next Node: HTTP Request"
URL: https://api.example.com/v1/resources
Method: GET
Headers:
Authorization: Bearer {{ $json.accessToken }}
```text
> **Warning: Store Secrets Securely**
>
> The example above stores client credentials in the Code node for clarity. In production, store `clientId` and `clientSecret` as n8n credentials or environment variables, not hardcoded in node parameters.
This pattern works with any OAuth2 API and eliminates manual token management. The workflow static data persists tokens across executions.
**Related:** [Use Path Parameters in Webhook URLs for Dynamic Routing](../webhook-mastery/01-use-path-parameters-in-webhook-urls-for-dynamic-routing.md) | [Use Edit Fields in "Map Each" Mode for Simple Renames](../data-transformation/01-use-edit-fields-in-map-each-mode-for-simple-renames.md)
I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.