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

# Refresh an expired access token

> Exchange a refresh token for a fresh user access token without re-minting from scratch.

User access tokens are short-lived JWTs. When one expires, exchange the refresh token you received alongside it for a new access token.

<Info>
  **Two different flows.** This page covers **API-key applications** operating on your own account. If you are an **OAuth platform application** acting on a customer's account, refresh customer tokens through the OAuth token refresh endpoint instead — see [Refresh an OAuth access token](/refresh-o-auth-access-token).
</Info>

## How the two tokens relate

```mermaid theme={null}
flowchart TD
    KEY[API key<br/>Basic auth]
    KEY -->|generateUserAccessToken| PAIR

    subgraph PAIR[One mint returns both]
        AT[access token<br/>short-lived]
        RT[refresh token<br/>long-lived]
    end

    AT -->|Bearer, every request| API[Fluz API]
    AT -.->|expires| EXP[401]
    RT -->|refreshUserAccessToken<br/>Basic auth| NEW[new access token only]
    NEW -->|Bearer| API
    RT -.->|reused, not replaced| RT

    style KEY fill:#e8e8e8,stroke:#888
    style AT fill:#d4edda,stroke:#5a9
    style NEW fill:#d4edda,stroke:#5a9
    style RT fill:#fff3cd,stroke:#c93
```

Two things catch people out. The refresh call authorizes with your **API key**, not with the expired access token. And it returns **only** a new access token — the refresh token you already hold stays valid and is not replaced.

## Where the refresh token comes from

`generateUserAccessToken` returns a refresh token alongside the access token. Request it explicitly — if you only select `token` and `scopes`, you never receive one:

```graphql theme={null}
mutation ($userId: UUID, $accountId: UUID, $scopes: [ScopeType!]!) {
  generateUserAccessToken(userId: $userId, accountId: $accountId, scopes: $scopes) {
    token
    refreshToken
    scopes
  }
}
```

Store the `refreshToken` server-side with the access token. See [API credentials](/get-started/api-credentials) for the full minting call.

## Refresh the token

`refreshUserAccessToken` authorizes with your **API key**, not with the expired access token.

<Steps>
  <Step title="Call refreshUserAccessToken">
    Replace `<YOUR_SANDBOX_API_KEY>` and `<YOUR_REFRESH_TOKEN>` with your values:

    ```bash theme={null}
    curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
      -H "Authorization: Basic <YOUR_SANDBOX_API_KEY>" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation ($refreshToken: String!) { refreshUserAccessToken(refreshToken: $refreshToken) { token scopes } }",
        "variables": {
          "refreshToken": "<YOUR_REFRESH_TOKEN>"
        }
      }'
    ```
  </Step>

  <Step title="Store the new access token">
    The response carries a fresh access token and the scopes it grants:

    ```json theme={null}
    {
      "data": {
        "refreshUserAccessToken": {
          "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
          "scopes": ["LIST_OFFERS", "PURCHASE_GIFTCARD"]
        }
      }
    }
    ```

    Use the new `token` in the `Authorization: Bearer <YOUR_USER_ACCESS_TOKEN>` header, exactly as before.
  </Step>
</Steps>

<Note>
  **The refresh response does not include a new refresh token.** `refreshUserAccessToken` returns only `token` and `scopes`. Keep the refresh token you received from `generateUserAccessToken`.
</Note>

## When to refresh

Refresh proactively — at the start of a job or session — rather than waiting for a request to fail with a `401` and refreshing reactively. That keeps requests from failing under load.

If you no longer hold a valid refresh token, mint a new access token from scratch with [`generateUserAccessToken`](/get-started/api-credentials).

## Next steps

<CardGroup cols={2}>
  <Card title="API credentials" icon="key" href="/get-started/api-credentials">
    Mint your first access token and see the full set of arguments.
  </Card>

  <Card title="Authentication" icon="shield-check" href="/concepts/authentication">
    The complete authentication model, including OAuth grants for customer-scoped tokens.
  </Card>
</CardGroup>
