Use the OAuth 2.0 client credentials flow to obtain an access token for machine-to-machine (M2M) authentication in Alibaba Cloud IDaaS (EIAM). This page provides request and response examples for each supported authentication method.
Choose an authentication method
All methods POST to the same token endpoint. Select the method that matches your application's credential type.
| Method | Credential type | Security level | Use when |
|---|---|---|---|
client_secret_basic | Shared secret (HTTP Basic) | Standard | Simple integrations where the secret is sent in the Authorization header |
client_secret_post | Shared secret (request body) | Standard | Clients that cannot set custom headers |
client_secret_jwt | Shared secret, JWT-signed (HS256) | Higher | You want to avoid transmitting the raw secret on the wire |
private_key_jwt | RSA private key, JWT-signed (RS256) | Highest | Production systems requiring asymmetric key security |
| OIDC federated authentication | External OIDC token | High | Your service already holds an OIDC token from an identity provider (e.g., Alibaba Cloud ACK) |
| PKCS#7 signature authentication | PKCS#7 signature | High | Your system generates PKCS#7 signatures (e.g., hardware security modules) |
| Private CA certificate authentication | X.509 client certificate | High | Your infrastructure uses a private certificate authority |
Prerequisites
Before you begin, make sure you have:
An IDaaS EIAM instance with M2M configured
An application ID (
client_id) and, depending on your method, the corresponding credentials (client secret, private key, or certificate)At least one resource server and scope configured in IDaaS EIAM
The token endpoint URL for your instance:
https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token
Token endpoint
All methods send a POST request to the same endpoint:
POST https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/tokenAuthentication methods
client_secret_basic
Encode the client_id and client_secret as a Base64 string and pass it in the Authorization header.
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Authorization | String | Yes | Basic followed by the Base64-encoded string of <client_id>:<client_secret> | Basic YXBwX201ZG9vemVzbm81Mmtxxxxxxxxx |
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|read:file |
client_id | String | Yes | The application ID | app_m5doozesno52kbqrqpw3xxxx |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Authorization: Basic <base64-encoded-client-id-and-secret>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=api://api.example.com|read:file'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2sep******HBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}client_secret_post
Pass the client_id and client_secret directly in the request body. No Authorization header is needed.
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | app_m5doozesno52kbqrqpw3xxxx |
client_secret | String | Yes | The application secret | CS5v3F4Cy8hyDmFPJtAuyHDTUdR8i88GcgcXXXXX |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|read:file |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'client_secret=<your-client-secret>' \
--data-urlencode 'scope=api://api.example.com|read:file'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2******kxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}client_secret_jwt
Sign a JWT using your client_secret (HS256 algorithm) and pass it as the client_assertion. The raw secret is never sent on the wire.
See Appendix 2: Generate a JWT signature using Java (HS256) for a complete code example.
JWT claims required in the `client_assertion`
| Claim | Description | Value |
|---|---|---|
iss | Issuer | Your client_id |
sub | Subject | Your client_id |
aud | Audience | The token endpoint URL |
exp | Expiration | Must not exceed 30 minutes from issuance |
jti | JWT ID | A unique UUID per request (anti-replay) |
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | |
client_assertion_type | String | Yes | Always urn:ietf:params:oauth:client-assertion-type:jwt-bearer | |
client_assertion | String | Yes | The JWT signed with the client_secret using HS256 | |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|read:file |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=<your-jwt-token>' \
--data-urlencode 'scope=api://api.example.com|read:file'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2se******NHBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}private_key_jwt
Sign a JWT using your RSA private key (RS256 algorithm) and pass it as the client_assertion. This is the most secure option for production systems.
See Appendix 1: Generate a JWT signature using Java (RS256) for a complete code example.
JWT claims required in the `client_assertion`
| Claim | Description | Value |
|---|---|---|
iss | Issuer | Your client_id |
sub | Subject | Your client_id |
aud | Audience | The token endpoint URL |
exp | Expiration | Must not exceed 30 minutes from issuance |
jti | JWT ID | A unique UUID per request (anti-replay) |
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | |
client_assertion_type | String | Yes | Always urn:ietf:params:oauth:client-assertion-type:jwt-bearer | |
client_assertion | String | Yes | The JWT signed with the RSA private key using RS256 | |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|read:file |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=<your-jwt-token>' \
--data-urlencode 'scope=api://api.example.com|read:file'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2sep******NHBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}OIDC federated authentication
Use an existing OIDC token (issued by an external identity provider, such as Alibaba Cloud ACK) as the client_assertion. The application must have a matching federated credential configured in IDaaS EIAM.
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | |
client_assertion_type | String | Yes | Always urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer | |
client_assertion | String | Yes | The OIDC token in JWT format | |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|.all |
application_federated_credential_name | String | Yes | The name of the application's federated credential | aliyun_ack |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=api://api.example.com|.all' \
--data-urlencode 'application_federated_credential_name=<federated-credential-name>' \
--data-urlencode 'client_assertion=<your-oidc-token>' \
--data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2sep******7NHBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}PKCS#7 signature authentication
Use a PKCS#7 signature as the client_assertion. The application must have a matching federated credential configured in IDaaS EIAM.
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | |
client_assertion_type | String | Yes | Always urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer | |
client_assertion | String | Yes | The PKCS#7 signature value | |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|.all |
application_federated_credential_name | String | Yes | The name of the application's federated credential | aliyun_ecs |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=api://api.example.com|.all' \
--data-urlencode 'application_federated_credential_name=<federated-credential-name>' \
--data-urlencode 'client_assertion=<your-pkcs7-signature>' \
--data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2sep******7NHBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}Private CA certificate authentication
Present a JWT and X.509 certificate chain issued by your private CA. The application must have a matching federated credential configured in IDaaS EIAM.
Header parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | String | Yes | Always application/x-www-form-urlencoded | application/x-www-form-urlencoded |
Request parameters
| Parameter | Type | Required | Description | Example |
|---|---|---|---|---|
grant_type | String | Yes | Always client_credentials | client_credentials |
client_id | String | Yes | The application ID | |
client_assertion_type | String | Yes | Always urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer | |
client_assertion | String | Yes | A JWT issued by the client using the private key | |
scope | String | Yes | Space-separated list of scopes. Each scope uses the format <resourceServerIdentifier>|<scope>. To request all authorized scopes, use <resourceServerIdentifier>|.all. | api://api.example.com|.all |
client_x509 | String | Yes | The end-entity certificate (leaf certificate), Base64-encoded in DER format | -----BEGIN CERTIFICATE-----xxxxxx-----END CERTIFICATE----- |
client_x509_chain | String | Yes | Intermediate CA certificates, Base64-encoded in DER format, concatenated with line breaks. Each certificate must follow this format: -----BEGIN CERTIFICATE-----<certificate-content>-----END CERTIFICATE----- | |
application_federated_credential_name | String | Yes | The name of the application's federated credential | private_ca |
Request example
curl --request POST \
--url 'https://<instance-id>.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<your-client-id>' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'scope=api://api.example.com|.all' \
--data-urlencode 'application_federated_credential_name=<federated-credential-name>' \
--data-urlencode 'client_assertion=<your-jwt-token>' \
--data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer'Response parameters
| Parameter | Type | Nullable | Description |
|---|---|---|---|
access_token | String | No | The access token value |
expires_in | Long | No | Token lifetime in seconds |
expires_at | Long | No | Token expiration as a UNIX timestamp in seconds |
token_type | String | No | Always Bearer |
Response example
{
"token_type": "Bearer",
"access_token": "AT8csE2sepE******7NHBkxxHUG",
"expires_in": 3600,
"expires_at": 1733710213
}Error codes
| HTTP code | Error | Error message | Description |
|---|---|---|---|
| 400 | invalid_request | Require parameter variable: grant_type | A required parameter is missing, has an invalid value, appears more than once, or the request is otherwise malformed. |
| 400 | authentication_required | Authentication required, allowed authentication methods: [client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt] | The authentication method is not supported. Supported methods: client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt. |
| 400 | invalid_client_credential | Invalid client_assertion, reasons(s): [expired] | The client_assertion is invalid. The token has expired. |
| 400 | invalid_grant | Invalid or not supported grant_type: authorization_code | The grant_type value is not supported. |
| 400 | invalid_scope | Invalid scope: http://www.example.com|read:file | The requested scope is invalid, unknown, or malformed. |
| 500 | internal_error | Unexpected internal error | An internal server error occurred. |
Appendix 1: Generate a JWT signature using Java (RS256 algorithm)
Use this example to generate the client_assertion JWT for the private_key_jwt authentication method. The JWT is signed with an RSA private key using the RS256 algorithm.
Maven dependencies
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>Java code example
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class JwtGenerator {
private static final String PRIVATE_KEY = "your-private-key"; // Replace with your private key
// Enter the client_id of your application
private static final String ISSUER = "your_client_id";
// Enter the client_id of your application
private static final String SUBJECT = "your_client_id";
// Enter the token endpoint of your application
private static final String AUDIENCE = "your_token_endpoint";
public static void main(String[] args) throws Exception {
// Key
Key securityKey = RsaKeyConverter.getPrivateKeyFromString(PRIVATE_KEY);
Map<String, Object> claims = new HashMap<>();
claims.put("jti", UUID.randomUUID().toString()); // Anti-replay jti
// Set the expiration time. It cannot exceed 30 minutes.
long expirationTime = 1000 * 60 * 30;
Date expirationDate = new Date(System.currentTimeMillis() + expirationTime);
// Generate the JWT
String jwt = Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date())
.setExpiration(expirationDate)
.setSubject(SUBJECT)
.setIssuer(ISSUER)
.setAudience(AUDIENCE)
.signWith(securityKey, SignatureAlgorithm.RS256)
.compact();
System.out.println("Generated JWT:");
System.out.println(jwt);
}
}
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class RsaKeyConverter {
public static PrivateKey getPrivateKeyFromString(String privateKeyStr) throws Exception {
// Remove the PEM format header and footer
String privateKeyPEM = privateKeyStr
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", ""); // Remove all whitespace characters
// Base64 decode
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
// Generate the private key using PKCS8EncodedKeySpec
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
public static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception {
// Remove the PEM format header and footer
String publicKeyPEM = publicKeyStr
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", ""); // Remove all whitespace characters
// Base64 decode
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
// Generate the public key using X509EncodedKeySpec
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
}Appendix 2: Generate a JWT signature using Java (HS256 algorithm)
Use this example to generate the client_assertion JWT for the client_secret_jwt authentication method. The JWT is signed with the client_secret using the HS256 algorithm.
Maven dependencies
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>Java code example
public class JwtGenerator {
private static final String SECRET_KEY = "your_secret_key"; // Replace with your secret key
// Enter the client_id of your application
private static final String ISSUER = "your_client_id";
// Enter the client_id of your application
private static final String SUBJECT = "your_client_id";
// Enter the token endpoint of your application
private static final String AUDIENCE = "your_token_endpoint";
public static String generateJwt() throws Exception {
SecretKey secretKey = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
Map<String, Object> claims = new HashMap<>();
claims.put("jti", UUID.randomUUID().toString()); // Anti-replay jti
// Set the expiration time. It cannot exceed 30 minutes.
long expirationTime = 1000 * 60 * 30;
Date expirationDate = new Date(System.currentTimeMillis() + expirationTime);
// Generate the JWT
String jwt = Jwts.builder()
.setClaims(claims)
.setIssuedAt(new Date())
.setExpiration(expirationDate)
.setSubject(SUBJECT)
.setIssuer(ISSUER)
.setAudience(AUDIENCE)
.signWith(secretKey, SignatureAlgorithm.HS256)
.compact();
return jwt;
}
public static void main(String[] args) throws Exception{
// Generate the JWT
String jwt = generateJwt();
System.out.println("Generated JWT: " + jwt);
}
}