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

# API Authentication

> Get started with the Fynapse API by understanding authentication

## Overview

This article provides information on the authentication process for API calls.

Each API request made to Fynapse has to be authenticated. Fynapse uses OAuth2 Client Credentials authorization.

The Client Credentials Flow authorization occurs when an application exchanges its application credentials, such as client ID and client secret, for an access token from Fynapse.

#### How to Generate Client ID and Client Secret Parameters?

1. Go to [API Credentials](/documentation/instance-management/developers/api-credentials) in the **Developers** section of the menu.
2. Click **Create API credentials**, choose who owns the credentials, and confirm with **Create**.
3. In the **Save your secret** dialog, copy the **Client ID** and **Client Secret**, then click **Done**. Make sure to store the Client Secret securely, as you will not be able to see it again.

The diagram below shows the process of authenticating client credentials using a token:

```mermaid
sequenceDiagram
    participant C as Client
    participant RS as Resource Server
    participant AS as Authorization Server
    activate C
    C->>+AS: request access token
    AS-->>-C: access token
    C->>+RS: API request w/ access token
    RS->>+AS: validate access token
    AS-->>-RS: return
    RS->>RS: handle request
    RS-->>-C: return
    deactivate C
```

## Requesting Access Token

The access token can be obtained by sending a request to:

`https://<instance-url>/auth/token`

providing the *client id* and *secret* as parameters.

Example request and response below:

### Request

POST [https://api.fynapse.com/auth/token](https://api.fynapse.com/auth/token)

```curl
curl -X POST https://api.fynapse.com/auth/token \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=client_credentials" \
     -d "client_id=string" \
     -d "client_secret=string"
```

```python
import requests

url = "https://api.fynapse.com/auth/token"

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

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

print(response.json())
```

```javascript
const url = 'https://api.fynapse.com/auth/token';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  body: new URLSearchParams('')
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

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

func main() {

	url := "https://api.fynapse.com/auth/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))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.fynapse.com/auth/token")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/x-www-form-urlencoded'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.fynapse.com/auth/token")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.fynapse.com/auth/token', [
  'form_params' => null,
  'headers' => [
    'Content-Type' => 'application/x-www-form-urlencoded',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.fynapse.com/auth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Content-Type": "application/x-www-form-urlencoded"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.fynapse.com/auth/token")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Response (200)

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

## Refreshing the Access Token

The token response includes a `refresh_token` alongside the `access_token`. When the access token expires, use the refresh token to obtain a new one instead of starting a new session. Send the request to the same `POST /auth/token` endpoint with the `refresh_token` grant type:

```bash
curl -X POST "https://<instance-url>/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<refresh_token>" \
  -d "client_id=<client_id>" \
  -d "client_secret=<client_secret>"
```

The client ID and client secret are required for this call, in addition to the refresh token.

The diagram below shows the token refresh process:

```mermaid
sequenceDiagram
    participant C as Client
    participant RS as Resource Server
    participant AS as Authorization Server
    C->>AS: request new access token w/ refresh token
    AS-->>C: new access token + new refresh token
    C->>RS: API request w/ access token
    RS-->>C: return
```

The response has the same structure as the initial token response and includes a new refresh token. Two fields define how long the tokens remain valid:

* `expires_in` - the number of seconds until the access token expires
* `refresh_expires_in` - the number of seconds until the refresh token expires

> **Info**
>
> Always store and use the refresh token from the most recent response. Once the refresh token itself expires, request a new access token using the `client_credentials` grant type.

## Session Timeout

By default, the access token expires 5 minutes (300 seconds) after it is issued, and the refresh token expires after 30 minutes (1800 seconds). Each successful refresh returns a new refresh token, which keeps the session alive. The exact values for your environment are returned in the `expires_in` and `refresh_expires_in` fields of the token response.

## Errors

| Status Code | Description                                                                    |
| ----------- | ------------------------------------------------------------------------------ |
| 401         | Authentication error occurs with invalid credentials                           |
| 403         | Authorization error occurs when the user does not have authorization for login |