Skip to main content
Exchange an authorization code for an access token (and optionally an ID token if openid scope was requested). When the phone scope is granted, the ID token and userinfo response include phone_number and phone_number_verified. This must be done server-side — never expose your client secret in client-side code.
curl -X POST https://dhmad.tn/api/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE",
    "redirect_uri": "https://example.com/callback",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "code_verifier": "YOUR_CODE_VERIFIER"
  }'
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile email phone",
  "id_token": "eyJhbGciOiJIUzI1NiIs..."
}

Request Body

grant_type
string
required
Must be authorization_code
code
string
required
The authorization code received from the authorize endpoint callback
redirect_uri
string
required
Must exactly match the redirect_uri used in the authorization request
client_id
string
required
Your OAuth client ID
client_secret
string
required
Your OAuth client secret
code_verifier
string
PKCE code verifier (required if code_challenge was provided during authorization)

Response Fields

ID Token Claims

When openid scope is included, the ID token contains:
ClaimDescription
issIssuer (e.g., https://dhmad.tn)
subUser ID
audYour client ID
expExpiration timestamp
iatIssued-at timestamp
emailUser’s email address
email_verifiedWhether the email is verified
nameFull name
given_nameFirst name
family_nameLast name
kyc_verifiedWhether the user has approved KYC on DHMAD
kyc_statusKYC status: "pending", "approved", "rejected", or null

Error Responses

Unsupported grant type:
{
  "error": "unsupported_grant_type",
  "error_description": "Only 'authorization_code' grant type is supported"
}
Invalid or expired code:
{
  "error": "invalid_grant",
  "error_description": "Invalid or expired authorization code"
}
Invalid client credentials:
{
  "error": "invalid_client",
  "error_description": "Invalid client credentials"
}
Redirect URI mismatch:
{
  "error": "invalid_grant",
  "error_description": "Invalid redirect_uri. Must exactly match the URI used during authorization."
}
Invalid PKCE verifier:
{
  "error": "invalid_grant",
  "error_description": "Invalid code_verifier"
}

Authorization codes expire after 10 minutes and can only be used once. Exchange the code immediately after receiving it.