---
title: Refresh an access token
sidebar_label: Refresh an access token
sidebar_position: 4
description: Exchange a refresh token for a new access token and a new refresh token with POST /auth/refresh-token.
---

# Refresh an access token

| Method | Path |
| --- | --- |
| `POST` | `/auth/refresh-token` |

[Authentication](/authentication) · [Account routes](/authentication#account-routes)

Exchanges a refresh token for a new access token and a new refresh token. Call it before the access token expires to keep a session alive.

:::note
This is an account-level route. It has no `/auth/tenant/` variant. Use the `refreshToken` that a [tenant sign-in](/authentication) or registration returned.
:::

**Auth:** None. The refresh token in the body is the credential.
**Scope:** The session the refresh token belongs to.

## Request

### Body

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `refresh_token` | `string` | Yes | The refresh token of the session. At least 1 character. The name is in snake case. |

## Behaviour

- The answer holds `access_token`, `refresh_token` and `expires_in`, with snake case names. Sign-in answers use `accessToken` and `refreshToken`.
- Store the new `refresh_token` and use it for the next refresh.
- The access token is valid for one hour. `expires_in` is in seconds.
- A refresh token that the FHIR server rejects gives `400` with the FHIR server's description in `message`.
- A session of a patient whose project turned [`PATIENT_LOGIN_ENABLED`](/settings-and-features/settings/patient-login-enabled) off, or of a practitioner whose project turned [`PRACTITIONER_LOGIN_ENABLED`](/settings-and-features/settings/practitioner-login-enabled) off, gives `403` with `Login is not enabled for this project.` That ends the session: the refresh token is used up, and signing in again is refused while login is off.
- A practitioner who is a project admin is not refused, so a signed-in admin can still turn login back on. They cannot sign in again while it is off.
- The route is rate limited to 600 requests per minute for each caller. Over the limit the answer is `429`, which can sign a user out, so refresh once per token lifetime and not in a loop.

## Example

```bash
curl -X POST 'https://api.sandbox.ovok.com/auth/refresh-token' \
  -H 'Content-Type: application/json' \
  -d '{
    "refresh_token": "<refresh token from sign-in>"
  }'
```

## Successful response

`201` — A new token pair.

```json
{
  "access_token": "<new access token>",
  "refresh_token": "<new refresh token>",
  "expires_in": 3600
}
```

| Field | Type | Description |
| --- | --- | --- |
| `access_token` | `string` | Bearer access token. Valid for one hour. |
| `refresh_token` | `string` | The refresh token to use next. |
| `expires_in` | `integer` | Lifetime of the access token, in seconds. |

## Errors

| Status | Meaning |
| --- | --- |
| `400` | The refresh token is unknown, expired or revoked, or the token could not be refreshed. The message carries the FHIR server's description when there is one. |
| `403` | Login is switched off for the project of a patient or of a non-admin practitioner. The session ends. |
| `422` | `refresh_token` is missing or empty. |
| `429` | More than 600 requests in a minute from the same caller. |
