curl --request POST \
--url https://api.mudraid.ai/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data 'resource=<string>' \
--data 'scope=tasks:read tasks:write' \
--data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
--data 'client_assertion=<string>'import requests
url = "https://api.mudraid.ai/oauth2/token"
payload = {
"grant_type": "client_credentials",
"resource": "<string>",
"scope": "tasks:read tasks:write",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": "<string>"
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'client_credentials',
resource: '<string>',
scope: 'tasks:read tasks:write',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: '<string>'
})
};
fetch('https://api.mudraid.ai/oauth2/token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mudraid.ai/oauth2/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E",
CURLOPT_HTTPHEADER => [
"Content-Type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.mudraid.ai/oauth2/token"
payload := strings.NewReader("grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E")
req, _ := http.NewRequest("POST", url, payload)
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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mudraid.ai/oauth2/token")
.header("Content-Type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mudraid.ai/oauth2/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'
request.body = "grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E"
response = http.request(request)
puts response.read_body{
"access_token": "<string>",
"token_type": "Bearer",
"expires_in": 300,
"scope": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}Exchange machine-client credentials for an access token
The client_credentials grant for a machine client linked to an agent.
Authenticate with exactly one method:
private_key_jwt(RFC 7523) — sendclient_assertion_typeand aclient_assertionsigned with the client’s registered, activated key (RS256 or ES256). The assertion’sissandsubare theclient_id, itsaudis the exact token endpoint identifier, and it carriesiat, a shortexpand a uniquejti(replay-protected). The algorithm is pinned on the registered key, never taken from the assertion header alone.client_secret_basic— HTTP Basic with the client ID and secret. In production this needs a recorded, unexpired organization compatibility approval, re-checked at token time.
A client secret in the form body (client_secret_post) is not a
supported method and is refused as invalid_client.
The response is an RFC 9068 access token (typ: at+jwt, profile
mudraid-access-token-v2) whose aud is the requested resource and
whose scope is exactly the requested scopes. Linking a client grants
nothing on its own: the client needs an effective grant covering that
exact resource, and every requested scope must be covered by it — a
request naming any ungranted scope is refused whole as
invalid_scope, never silently narrowed. No refresh token is ever issued to a
machine client — re-authenticate for a new access token. Responses
carry Cache-Control: no-store.
authorization_code and refresh_token grants exist for the
human-delegation profile and are accepted only when enabled; read
grant_types_supported from the authorization-server metadata rather
than assuming them.
curl --request POST \
--url https://api.mudraid.ai/oauth2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data 'resource=<string>' \
--data 'scope=tasks:read tasks:write' \
--data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
--data 'client_assertion=<string>'import requests
url = "https://api.mudraid.ai/oauth2/token"
payload = {
"grant_type": "client_credentials",
"resource": "<string>",
"scope": "tasks:read tasks:write",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": "<string>"
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'client_credentials',
resource: '<string>',
scope: 'tasks:read tasks:write',
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: '<string>'
})
};
fetch('https://api.mudraid.ai/oauth2/token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mudraid.ai/oauth2/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E",
CURLOPT_HTTPHEADER => [
"Content-Type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.mudraid.ai/oauth2/token"
payload := strings.NewReader("grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E")
req, _ := http.NewRequest("POST", url, payload)
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(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mudraid.ai/oauth2/token")
.header("Content-Type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mudraid.ai/oauth2/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'
request.body = "grant_type=client_credentials&resource=%3Cstring%3E&scope=tasks%3Aread%20tasks%3Awrite&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=%3Cstring%3E"
response = http.request(request)
puts response.read_body{
"access_token": "<string>",
"token_type": "Bearer",
"expires_in": 300,
"scope": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>"
}Body
client_credentials for a machine client. Other grants are
accepted only when enabled — see grant_types_supported in the
authorization-server metadata.
client_credentials The exact approved resource URI (RFC 8707). Becomes the token's
aud.
Space-delimited requested scopes. Required and non-empty — an
absent or empty scope is invalid_scope, never a request for the
full entitlement. Every scope must be covered by an effective
grant for this resource.
"tasks:read tasks:write"
Required with client_assertion (private_key_jwt).
urn:ietf:params:oauth:client-assertion-type:jwt-bearer Signed RFC 7523 client assertion (private_key_jwt).
Response
Access token issued
RS256 at+jwt access token. See AccessTokenClaims.
Bearer Lifetime in seconds actually applied to this token. The default is
300 (five minutes). Operators can tune it, but the value is
hard-capped at the 900-second (fifteen-minute) ceiling — a
configured value above the ceiling is clamped down to it. Read the
lifetime from this field rather than assuming either number.
x <= 900The granted space-delimited scopes (the requested set).

