> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.bibleit.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.bibleit.dev/_mcp/server.

# Exchange a code or rotate a refresh token

POST https://bibleit.app/oauth/token
Content-Type: application/x-www-form-urlencoded

Public clients send client_id in form; Authorization headers are rejected. Authorization code binds client_id, exact redirect_uri and S256 verifier (43–128 unreserved ASCII characters), expires in 60 seconds, and is single-use. Refresh tokens require offline_access, rotate on every use, and retain the fixed 30-day grant deadline. Reusing a successfully exchanged code or used refresh token revokes the entire grant, including outstanding access/refresh tokens; no retry grace. Wrong client, redirect or verifier cannot exchange the code. Optional refresh scope permanently narrows the grant; it cannot widen. Current user permissions and client enabled status apply. Organization/service/PAT secrets are never issued. No implicit, password or client_credentials grant.

**Response headers:**

- `Cache-Control` (200).
- `Referrer-Policy` (200).
- `Pragma` (200).

Reference: https://docs.bibleit.dev/api-reference/o-auth/exchange-o-auth-token

## Request

### Body (application/x-www-form-urlencoded)

This endpoint expects an OAuth_exchangeOAuthToken_Request.

- `OAuth_exchangeOAuthToken_Request`

## Response

### 200

New opaque access token and optional rotating refresh token.

- `access_token` (string, required)
- `token_type` ("Bearer", required)
- `expires_in` (integer, required)
- `scope` (string, required)
- `refresh_token` (string, optional)

## Types

### OAuthExchangeOAuthTokenRequest0

- `grant_type` ("authorization_code", required)
- `client_id` (string, required)
- `code` (string, required)
- `redirect_uri` (string, required)
- `code_verifier` (string, required)

### OAuthExchangeOAuthTokenRequest1

- `grant_type` ("refresh_token", required)
- `client_id` (string, required)
- `refresh_token` (string, required)
- `scope` (string, optional) — Space-separated explicit registered personal scopes. No empty scope. offline_access alone is invalid.

## Examples

**Request**

```json
{
  "client_id": "string",
  "code": "string",
  "code_verifier": "string",
  "grant_type": "string",
  "redirect_uri": "string"
}
```

**Response**

```json
{
  "access_token": "string",
  "token_type": "string",
  "expires_in": 1,
  "scope": "string",
  "refresh_token": "string"
}
```

**SDK Code**

```python
import requests

url = "https://bibleit.app/oauth/token"

payload = ""
headers = {"Content-Type": "application/x-www-form-urlencoded"}

response = requests.post(url, data=payload, headers=headers)

print(response.json())
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://bibleit.app/oauth/token"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```