> ## Documentation Index
> Fetch the complete documentation index at: https://developers.pleo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Refresh Tokens

export const WhatComesNext = ({children, href}) => <div className="mt-4">
    <a href={href} className="
        inline-flex items-center justify-center
        rounded-full
        bg-black text-white dark:bg-[#1f262b]
        px-5 py-2.5 text-sm font-medium
        no-underline border-0
        hover:bg-[#ffe6ea] dark:hover:bg-[#2b1f23]
        hover:text-black
        transition-colors
      ">
      {children} →
    </a>
  </div>;

This how-to explains how to refresh OAuth 2.0 access tokens when they expire, allowing your integration to maintain continuous access to Pleo APIs without requiring users to reauthorise.

## Overview

Access tokens issued by Pleo are **short-lived**.\
To continue calling Pleo APIs, your integration must use the **refresh token** to obtain a new access token when the current one expires.

Refreshing tokens:

* Happens without user interaction
* Must be handled server-side
* Must be safe against race conditions and retries

## Steps

### 1. Determine When to Refresh Tokens

Your integration should refresh the access token when:

* The token is **about to expire** (preferred), or
* An API call fails due to token expiration

Use the `expires_in` value returned during token exchange to track expiry.

<Tip>
  Refreshing tokens slightly before expiry reduces the risk of failed API calls during active workflows.
</Tip>

***

### 2. Send a Refresh Token Request

To refresh tokens, make a request to Pleo’s token endpoint using the **refresh token grant**.

The request must include:

* `grant_type`: `refresh_token`
* `refresh_token`: the current refresh token
* `client_id`
* `client_secret`

The request must be sent from a **secure backend service** over HTTPS.

***

### 3. Handle the Token Refresh Response

A successful refresh response returns:

* A new **access token**
* A new **refresh token**
* A new `expires_in` value

Your integration must:

* Replace the stored access token
* Replace the stored refresh token
* Update the expiry timestamp

<Tip>
  Always persist both tokens after a successful refresh. Refresh tokens are rotated and old ones may no longer be valid.
</Tip>

***

### 4. Centralise Token Refresh Logic

Token refresh must be implemented in a **single, centralised location** within your integration.

This ensures:

* Consistent behaviour across all API calls
* Easier monitoring and debugging
* Correct handling of retries and failures

For design requirements, see [Centralised Token Refresh](/docs/current/integration-design/auth/oauth/token-lifecycle/integration-design-auth-oauth-centralised-token-refresh).

***

### 5. Prevent Race Conditions

Multiple concurrent processes may detect token expiry at the same time.

Your integration must ensure:

* Only **one refresh request** is made at a time
* Other requests wait for the refreshed token

Common approaches include:

* Distributed locks
* In-memory mutexes
* Database-level locks

For design requirements, see [Race Condition Prevention](/docs/current/integration-design/auth/oauth/token-lifecycle/integration-design-auth-oauth-race-condition-prevention).

***

### 6. Handle Refresh Failures

Token refresh may fail due to:

* Expired refresh token
* Revoked access
* Invalid client credentials

If a refresh attempt fails:

* Do **not** retry indefinitely
* Do **not** continue making API calls
* Mark the token state as invalid

Your integration must require the user to reauthorise.

***

### 7. Log Refresh Activity

Your integration should log:

* Refresh attempts (timestamped)
* Success or failure outcomes
* Failure reasons (where available)

These logs are critical for diagnosing authentication and session issues.

***

## Result

After completing these steps:

* Your integration refreshes access tokens without user involvement
* API access continues seamlessly across token expirations
* Token refresh behaviour is predictable, safe, and observable

***

## What Comes Next?

<WhatComesNext href="/docs/current/how-tos/oauth/how-to-handle-token-expiry-or-revocation">
  Learn how to recover safely when refresh tokens expire or access is revoked
</WhatComesNext>

***

<div className="text-xs uppercase" style={{ fontVariant: 'small-caps' }}>
  this how-to is part of:
</div>

<div className="mt-4 flex flex-wrap gap-2">
  <a
    href="/docs/current/guides/oauth-workflow-guide"
    className="inline-flex items-center rounded-full border border-gray-300 dark:border-gray-600 
px-3 py-1 text-xs font-medium 
bg-white dark:bg-[#1f262b] text-black dark:text-white
hover:bg-gray-100 dark:hover:bg-[#2b2f33]
transition-colors"
  >
    OAuth 2.0 Setup Workflow Guide (Manual Token Lifecycle)
  </a>
</div>

***

## Related Reading

* [Token Lifecycle](/docs/current/integration-design/auth/oauth/token-lifecycle/integration-design-auth-oauth-token-overview)
* [OAuth 2.0 Client Registration](/docs/current/integration-design/auth/oauth/getting-set-up/oauth-client-registration) – Step-by-step details of required fields, credentials, and redirect URIs.
* [OAuth 2.0 Client Configuration](/docs/current/integration-design/auth/oauth/getting-set-up/oauth-client-configuration) – How to configure your client with correct endpoints, PKCE, and authentication methods.
* [PKCE and Secured Patterns](/docs/current/integration-design/auth/oauth/implementing-oauth/integration-design-auth-oauth-pkce-and-secured-patterns) – Security requirements for public clients.

***
