Skip to main content
POST
/
oauth
/
token
Exchange authorization code or refresh token for access token
curl --request POST \
  --url https://app.profy.cn/oauth/token \
  --header 'Content-Type: application/json' \
  --data '
{
  "client_id": "your-app-uuid",
  "client_secret": "<string>",
  "code": "<string>",
  "redirect_uri": "https://your-app.com/callback",
  "refresh_token": "<string>"
}
'
import requests

url = "https://app.profy.cn/oauth/token"

payload = {
"client_id": "your-app-uuid",
"client_secret": "<string>",
"code": "<string>",
"redirect_uri": "https://your-app.com/callback",
"refresh_token": "<string>"
}
headers = {"Content-Type": "application/json"}

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

print(response.text)
const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
client_id: 'your-app-uuid',
client_secret: '<string>',
code: '<string>',
redirect_uri: 'https://your-app.com/callback',
refresh_token: '<string>'
})
};

fetch('https://app.profy.cn/oauth/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://app.profy.cn/oauth/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 => json_encode([
'client_id' => 'your-app-uuid',
'client_secret' => '<string>',
'code' => '<string>',
'redirect_uri' => 'https://your-app.com/callback',
'refresh_token' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);

$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://app.profy.cn/oauth/token"

payload := strings.NewReader("{\n \"client_id\": \"your-app-uuid\",\n \"client_secret\": \"<string>\",\n \"code\": \"<string>\",\n \"redirect_uri\": \"https://your-app.com/callback\",\n \"refresh_token\": \"<string>\"\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(string(body))

}
HttpResponse<String> response = Unirest.post("https://app.profy.cn/oauth/token")
.header("Content-Type", "application/json")
.body("{\n \"client_id\": \"your-app-uuid\",\n \"client_secret\": \"<string>\",\n \"code\": \"<string>\",\n \"redirect_uri\": \"https://your-app.com/callback\",\n \"refresh_token\": \"<string>\"\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://app.profy.cn/oauth/token")

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 \"client_id\": \"your-app-uuid\",\n \"client_secret\": \"<string>\",\n \"code\": \"<string>\",\n \"redirect_uri\": \"https://your-app.com/callback\",\n \"refresh_token\": \"<string>\"\n}"

response = http.request(request)
puts response.read_body
{
  "access_token": "<string>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "<string>",
  "scope": "<string>"
}
{
"error": "invalid_client",
"error_description": "Missing client credentials"
}
{
"error": "invalid_client",
"error_description": "Missing client credentials"
}
client_id and client_secret must be passed in the request body. Basic Auth header is not supported.

Usage

1. Exchange Authorization Code for Token

After the user approves on the consent page, your redirect_uri receives a code parameter. Exchange it for an access token:
curl --request POST \
  --url https://app.profy.cn/oauth/token \
  --header 'Content-Type: application/json' \
  --data '{
    "grant_type": "authorization_code",
    "code": "auth-code-from-callback",
    "redirect_uri": "https://your-app.com/callback",
    "client_id": "your-app-uuid",
    "client_secret": "your-app-secret"
  }'

2. Refresh an Expired Token

Access tokens expire after 1 hour. Use the refresh token to get a new token pair:
curl --request POST \
  --url https://app.profy.cn/oauth/token \
  --header 'Content-Type: application/json' \
  --data '{
    "grant_type": "refresh_token",
    "refresh_token": "your-refresh-token",
    "client_id": "your-app-uuid",
    "client_secret": "your-app-secret"
  }'
Refresh tokens are rotated on each use — the old token is immediately invalidated. Always save the new refresh_token from the response.

Common Errors

ErrorCause
Missing client credentialsRequest body missing client_id or client_secret
Invalid client credentialsclient_id not found or client_secret mismatch
Invalid or expired authorization codeAuth code expired (5 min TTL) or already used
redirect_uri mismatchredirect_uri doesn’t match the one from the authorization request
Invalid or expired refresh tokenRefresh token invalid, expired (90 days), or already rotated

Body

grant_type
enum<string>
required

OAuth grant type

Available options:
authorization_code,
refresh_token
client_id
string
required

Your application UUID

Example:

"your-app-uuid"

client_secret
string
required

Your application secret (plaintext)

code
string

Authorization code from the callback redirect (required when grant_type=authorization_code)

redirect_uri
string

Must exactly match the redirect_uri used in the authorization request (required when grant_type=authorization_code)

Example:

"https://your-app.com/callback"

refresh_token
string

Refresh token from a prior token response (required when grant_type=refresh_token)

Response

Token pair issued

access_token
string
required
token_type
string
required
Example:

"Bearer"

expires_in
number
required
Example:

3600

refresh_token
string
required
scope
string
required