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

# OAuth · Approve authorization

POST https://api.modulards.com/oauth/authorize
Content-Type: application/json

Approves the pending OAuth authorization from the dashboard consent screen (Passport session endpoint).

`auth_token` is the single-use nonce the authorize redirect handed to the dashboard (`GET /oauth/authorize` → 302 to `{front}/oauth/authorize?auth_token=…`). It is bound to the web session: this endpoint needs the dashboard session cookie plus `X-XSRF-TOKEN` — a personal access token never authenticates it.

**Body** (JSON):

* `auth_token` — the nonce above. Passport compares it with the session and answers a missing or stale one with its own 403.
* `read_only` (boolean, required) — the level the consent screen's selector chose: `true` only reads, `false` reads and makes changes. It is stored for the user and this client once the code is issued, and preselects it on the next consent screen for the same app. Any other field in the body is rejected (422).

**Responses**:

* With `Accept: application/json` (what the SPA sends): **200** `{"redirect": url}` — the client callback carrying `code` and `state`. The SPA navigates there itself, top level, because a cross-origin XHR cannot follow a 302 to the client's origin (`ConvertsAuthorizationRedirectToJson`).
* Without it (plain navigation): **302** with the same URL in `Location`.
* Expired, unknown or reused `auth_token`: **403** — the nonce is single use, and the SPA renders its own invalid state for this status.
* `read_only` missing or not a boolean: **422** — the request stays pending and can be retried with the same `auth_token`.
* While an administrator impersonates the user: **404** with `Credentials cannot be created while impersonating a user.` — approving is refused outright, whatever `read_only` was sent.

Host root, no `/api` prefix.

Reference: https://api.docs.modulards.com/modular-ds-public-api/oauth/oauth-approve-authorization

## Request

### Body (application/json)

This endpoint expects an object.

- `auth_token` (string, optional)
- `read_only` (boolean, optional)

## Response

### 200

200 OK · redirect as data

- `redirect` (string, optional)

## Errors

### 403 Forbidden Error

403 Forbidden · invalid auth token

- `errors` (list of OauthAuthorizePostResponsesContentApplicationJsonSchemaErrorsItems, optional)
- `jsonapi` (OauthAuthorizePostResponsesContentApplicationJsonSchemaJsonapi, optional)

### 422 Unprocessable Entity Error

422 Unprocessable · missing read_only

- `errors` (OauthAuthorizePostResponsesContentApplicationJsonSchemaErrors, optional)
- `message` (string, optional)

## Types

### OauthAuthorizePostResponsesContentApplicationJsonSchemaErrorsItems

- `detail` (string, optional)
- `status` (string, optional)
- `title` (string, optional)

### OauthAuthorizePostResponsesContentApplicationJsonSchemaJsonapi

- `version` (string, optional)

### OauthAuthorizePostResponsesContentApplicationJsonSchemaErrors

- `read_only` (list of string, optional)

## Examples

### 200 OK · redirect as data

**Response**

```json
{
  "redirect": "https://claude.ai/api/mcp/auth_callback?code=def50200d4d3f39d823e0a3b3148f02b&state=client-state-123"
}
```

**SDK Code**

```python 200 OK · redirect as data
import requests

url = "https://api.modulards.com/oauth/authorize"

response = requests.post(url)

print(response.json())
```

```javascript 200 OK · redirect as data
const url = 'https://api.modulards.com/oauth/authorize';
const options = {method: 'POST'};

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

```go 200 OK · redirect as data
package main

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

func main() {

	url := "https://api.modulards.com/oauth/authorize"

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

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

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

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

}
```

```ruby 200 OK · redirect as data
require 'uri'
require 'net/http'

url = URI("https://api.modulards.com/oauth/authorize")

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

request = Net::HTTP::Post.new(url)

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

```java 200 OK · redirect as data
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.modulards.com/oauth/authorize")
  .asString();
```

```php 200 OK · redirect as data
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.modulards.com/oauth/authorize');

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

```csharp 200 OK · redirect as data
using RestSharp;

var client = new RestClient("https://api.modulards.com/oauth/authorize");
var request = new RestRequest(Method.POST);
IRestResponse response = client.Execute(request);
```

```swift 200 OK · redirect as data
import Foundation

let request = NSMutableURLRequest(url: NSURL(string: "https://api.modulards.com/oauth/authorize")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"

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()
```

### OAuth · Approve authorization

**Request**

```json
{
  "auth_token": "<auth_token from the consent screen URL>",
  "read_only": true
}
```

**Response**

```json
{
  "redirect": "https://claude.ai/api/mcp/auth_callback?code=def50200d4d3f39d823e0a3b3148f02b&state=client-state-123"
}
```

**SDK Code**

```python OAuth · Approve authorization
import requests

url = "https://api.modulards.com/oauth/authorize"

payload = {
    "auth_token": "<auth_token from the consent screen URL>",
    "read_only": True
}
headers = {"Content-Type": "application/json"}

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

print(response.json())
```

```javascript OAuth · Approve authorization
const url = 'https://api.modulards.com/oauth/authorize';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: '{"auth_token":"<auth_token from the consent screen URL>","read_only":true}'
};

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

```go OAuth · Approve authorization
package main

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

func main() {

	url := "https://api.modulards.com/oauth/authorize"

	payload := strings.NewReader("{\n  \"auth_token\": \"<auth_token from the consent screen URL>\",\n  \"read_only\": true\n}")

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

	req.Header.Add("Content-Type", "application/json")

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

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

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

}
```

```ruby OAuth · Approve authorization
require 'uri'
require 'net/http'

url = URI("https://api.modulards.com/oauth/authorize")

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

request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n  \"auth_token\": \"<auth_token from the consent screen URL>\",\n  \"read_only\": true\n}"

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

```java OAuth · Approve authorization
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.modulards.com/oauth/authorize")
  .header("Content-Type", "application/json")
  .body("{\n  \"auth_token\": \"<auth_token from the consent screen URL>\",\n  \"read_only\": true\n}")
  .asString();
```

```php OAuth · Approve authorization
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.modulards.com/oauth/authorize', [
  'body' => '{
  "auth_token": "<auth_token from the consent screen URL>",
  "read_only": true
}',
  'headers' => [
    'Content-Type' => 'application/json',
  ],
]);

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

```csharp OAuth · Approve authorization
using RestSharp;

var client = new RestClient("https://api.modulards.com/oauth/authorize");
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"auth_token\": \"<auth_token from the consent screen URL>\",\n  \"read_only\": true\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift OAuth · Approve authorization
import Foundation

let headers = ["Content-Type": "application/json"]
let parameters = [
  "auth_token": "<auth_token from the consent screen URL>",
  "read_only": true
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.modulards.com/oauth/authorize")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

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()
```