Get an access_token
Obtain the app-level access_token. A third-party app backend exchanges the token with the client_credentials grant and uses it to call open APIs for members, organization structure, enterprise information, and robots.
API information
| Item | Description |
|---|---|
| API name | Get an access_token |
| HTTP method | POST |
| Endpoint | https://{gateway_host}/auth/v1/oauth/token |
| Data format | application/json |
| Authentication | None; the app credential is exchanged for the token |
| Cross-origin | Browser cross-origin requests are supported; Access-Control-Allow-Credentials is not returned. The App Secret must still never be sent to a browser. |
Prerequisites
- The app has been created and published under "Internal Apps" in the admin console.
AppId(theclient_id) andAppSecret(theclient_secret) are available in the app details under "Credentials and basic information".- Store
AppSecretonly in the app backend; never send it to a frontend or client.
Request parameters
Request headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Fixed to application/json |
Request body
{
"client_id": "app_10001",
"client_secret": "link_xxxxxxxxx",
"grant_type": "client_credentials"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id | string | Yes | App AppId |
client_secret | string | Yes | App AppSecret |
grant_type | string | Yes | Grant type, fixed to client_credentials |
Response parameters
Successful response (the standard OAuth JSON envelope without the platform {code,msg,data} wrapper):
{
"access_token": "opaque-app-access-token",
"expires_in": 7200
}
| Field | Type | Description |
|---|---|---|
access_token | string | App-level credential token, valid for 7200 seconds by default (2 hours) |
expires_in | integer | Remaining credential validity, in seconds |
Token usage rules
- Reuse and caching: Reuse
access_tokenduring its validity period. The app backend should cache it centrally and refresh it early, for example when five minutes remain, to avoid frequent calls to this API. - Credential isolation:
access_tokenis an app-level credential, not a user session. Do not put it in cookies, send it to clients, or use it as the business system's own Bearer token. - Secret rotation: When an administrator rotates
AppSecret, everyaccess_tokenissued with the old secret becomes invalid immediately. Request a new token with this API. - Transport: When calling open APIs, send the token in
Authorization: Bearer <access_token>where possible. Some APIs also support the query parameter?access_token=<access_token>.
Error codes
Token exchange failures are returned with an HTTP status code and the OAuth error field:
{
"error": "INVALID_CLIENT",
"error_description": "invalid client credentials"
}
| HTTP status | error code | Meaning and suggested handling |
|---|---|---|
| 400 | INVALID_REQUEST | The request is not valid JSON, grant_type is not client_credentials, or a required field is missing. |
| 401 | INVALID_CLIENT | The app does not exist, is disabled/deleted, or client_id and client_secret do not match. |
| 500 | SERVER_ERROR | Server error; retry later. |
Multilingual call examples
The following examples run on the server; never send app secrets or app tokens to a client.
Shell
curl -sS -X POST "https://{gateway_host}/auth/v1/oauth/token" \
-H "Content-Type: application/json" \
-d '{"client_id":"app_10001","client_secret":"link_xxxxxxxxx","grant_type":"client_credentials"}'
PHP
<?php
// Check the HTTP status and response body in production before mapping business errors.
$handle = curl_init('https://{gateway_host}/auth/v1/oauth/token');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"client_id":"app_10001","client_secret":"link_xxxxxxxxx","grant_type":"client_credentials"}',
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($handle);
curl_close($handle);
Golang
package main
import (
"bytes"
"net/http"
)
func main() {
// Use the token only in a server-side request and send it as specified by the API.
request, _ := http.NewRequest(http.MethodPost, "https://{gateway_host}/auth/v1/oauth/token", bytes.NewBufferString(`{"client_id":"app_10001","client_secret":"link_xxxxxxxxx","grant_type":"client_credentials"}`))
request.Header.Set("Content-Type", "application/json")
response, _ := http.DefaultClient.Do(request)
defer response.Body.Close()
}
C++
#include <curl/curl.h>
int main() {
// Enable TLS verification and handle HTTP errors in production.
CURL* handle = curl_easy_init();
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(handle, CURLOPT_URL, "https://{gateway_host}/auth/v1/oauth/token");
curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, R"({"client_id":"app_10001","client_secret":"link_xxxxxxxxx","grant_type":"client_credentials"})");
const CURLcode result = curl_easy_perform(handle);
curl_slist_free_all(headers);
curl_easy_cleanup(handle);
return result == CURLE_OK ? 0 : 1;
}