> Source: https://wexa.ai/docs/tools/refresh-session

# refresh-session

Trade an SDK session's refresh token for a new access token and a new refresh token. The old refresh token stops working at once. Both SDKs do this for you shortly before the access token runs out, and again if a call comes back with an expired token, so you only call it yourself when you want to control the timing. Save every new pair: the SDKs pass it to your token callback.

A refresh token works exactly once. If one is presented a second time, Wexa treats it as stolen and ends the whole session; log the user in again.

## What it is called on each surface

`refresh-session` is not on the Wexa MCP server, because it belongs to an SDK session and MCP clients sign in through OAuth.

| Surface | Name |
| --- | --- |
| REST API | `POST /v1/auth/refresh` |
| TypeScript SDK | `fabric.auth.refresh()` |
| Python SDK | `fabric.auth.refresh()` |

## Arguments

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `refresh_token` | string | Required | The newest refresh token of the session. The SDKs send it for you and take no arguments. |

## What it returns

A real response, captured from a live call to `refresh-session`. The session id stays the same; both tokens are new. The tokens are cut short here:

**Result of refresh-session**

**REST API**

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
  "refresh_token": "fab_srt_ixnbhT…",
  "token_type": "Bearer",
  "expires_in": 3600,
  "org_id": "6a79a770b6c128ccc24bfca8",
  "project_id": "6aa9beb7ec8121a43b6c791b",
  "session_id": "sess_Ss5LcvniPbkIkWERMiY8YUAO",
  "grants": ["fabric:query.read", "fabric:docs.read", "fabric:orchestrate.read", "fabric:model.run"]
}
```

**TypeScript SDK**

```ts
{
  accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…',
  refreshToken: 'fab_srt_ixnbhT…',
  expiresAt: 1790257200
}
```

**Python SDK**

```python
{
 "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
 "refresh_token": "fab_srt_ixnbhT…",
 "expires_at": 1790257200.0
}
```

`grants` is shortened here; the real response lists every grant the user's current role gives, or the narrowed list from [login](/docs/tools/login).

## Calling it

**Call refresh-session**

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/auth/refresh \
  -H "content-type: application/json" \
  -d '{"refresh_token": "'"$FABRIC_REFRESH_TOKEN"'"}'
```

**TypeScript SDK**

```ts
const tokens = await fabric.auth.refresh()
```

**Python SDK**

```python
tokens = fabric.auth.refresh()
```

## Errors

| Error | Status | Raised when |
| --- | --- | --- |
| `AuthError` | 401 | The session has ended (`invalid_grant`): it was logged out, revoked by an admin or by the user, ended by a password reset, password change, suspension or account removal, or the refresh token was already used or has expired. Log the user in again. |
| `ForbiddenError` | 403 | The user is no longer a member of the project, or the call came from a browser origin that is not allowed. |
| `ValidationError` | 400 | No refresh token was sent. |
| `UpstreamError` | 502 | The account service behind the gateway could not be reached. The refresh token is not used up, so retrying later can help. |
| `ConfigurationError` | — | Raised in the SDK: the client was built with an API key, which has nothing to refresh. |

## Governance

Not a governed tool: it runs before any tool call. Each refresh checks the user's membership and role in the project again.

## See also

[login](/docs/tools/login), [logout](/docs/tools/logout), and [the tool index](/docs/tools/overview).
