This topic provides call examples for M2M client tokens in Alibaba Cloud IDaaS (EIAM). It describes how to obtain an access token through the OAuth 2.0 Client Credentials Flow and call APIs to implement secure authentication between systems.
Call examples
Authentication method: client_secret_basic
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Authorization
String
The value is the Base64 encoding of clientId and clientSecret joined together. The join format is clientId:clientSecret.
YXBwX201ZG9vemVzbm81Mmtxxxxxxxxx
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
client_id
string
The application ID.
Request example:
curl --location --request POST 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Authorization: Basic YXBwX201ZG9vemVxxxxxx' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'api://api.xxxxx.com|read:file'Response parameters:
Parameter
Type
Nullable
Description
access_token
String
No
The token value.
expires_in
Long
No
The validity period, in seconds.
expires_at
Long
No
The expiration time, as a UNIX timestamp, in seconds.
token_type
String
No
The token type.
Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2s******kxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: client_secret_post
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_secret
String
The application secret.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
Request example:
curl --location --request POST 'https://XXXX.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=app_m5doozesno52kbqrqpw3XXXX' \ --data-urlencode 'client_secret=CS5v3F4Cy8hyDmFPJtAuyHDTUdR8i88GcgcXXXXX' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2s******NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: client_secret_jwt
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_assertion_type
String
The client assertion type. Fixed value: urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
client_assertion
String
The signature issued by the client using client_secret, in JWT format. The signature algorithm is HS256. See Appendix 2.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
Request example:
curl --request POST \ --url 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id={{clientId}}' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'client_assertion={{JwtToken}}' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2s******kxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: private_key_jwt
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_assertion_type
String
The client assertion type. Fixed value: urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
client_assertion
String
The signature issued by the client using the private key, in JWT format. The signature algorithm is RS256. See Appendix 1.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
Request example:
curl --request POST \ --url 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id={{clientId}}' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'client_assertion={{JwtToken}}' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2se******BkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: OIDC federated authentication
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_assertion_type
String
The client assertion type. Fixed value: urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer.
client_assertion
String
The OIDC token used by the client, in JWT format.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
application_federated_credential_name
String
The name of the application's federated credential.
aliyun_ack
Request example:
curl --request POST \ --url https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxxx' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxxx' \ --data-urlencode 'client_assertion=xxxxx.xxxxx.xxxxx' \ --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
The validity period, as a UNIX timestamp, in seconds.
expires_at
Long
No
The expiration time, as a UNIX timestamp, in seconds.
token_type
String
No
The access token type.
Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2se******NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: PKCS#7 signature authentication
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_assertion_type
String
The client assertion type. Fixed value: urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer.
client_assertion
String
The PKCS#7 signature value.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use {resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
application_federated_credential_name
String
The name of the application's federated credential.
aliyun_ecs
Request example:
curl --request POST \ --url 'https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxx' \ --data-urlencode 'grant_type=client_credentials \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxxx' \ --data-urlencode 'client_assertion=xxxxx' \ --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
The validity period, as a UNIX timestamp, in seconds.
expires_at
Long
No
The expiration time, as a UNIX timestamp, in seconds.
token_type
String
No
The access token type.
Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2sep******HBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Authentication method: PrivateCA certificate authentication
Request method: POST
Header parameters:
Parameter
Type
Description
Example
Content-Type
String
Fixed value: application/x-www-form-urlencoded.
application/x-www-form-urlencoded
Request parameters:
Parameter
Type
Description
Example
grant_type
String
Fixed value: client_credentials.
client_credentials
client_id
String
The application ID.
client_assertion_type
String
The client assertion type. Fixed value: urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer.
client_assertion
String
The JWT token issued by the client using private_key.
scope
String
You can request permissions by scope. String values are joined with spaces. The format is resourceServerIdentifier+"|"+scope. For example:
resourceServerIdentifier is api://api.xxxxx.com, and scope is read:file.
The final result is api://api.xxxxx.com|read:file.
To obtain all scopes already authorized for the current client, use:
api://api.xxxxx.com|read:file
client_x509
String
The end-entity certificate (leaf certificate), that is, the client certificate.
base64-encoded Distinguished Encoding Rules
-----BEGIN CERTIFICATE-----
xxxxxx
-----END CERTIFICATE-----
client_x509_chain
String
The list of intermediate certificates, Intermediate CA.
base64-encoded Distinguished Encoding Rules
Join multiple certificates with line breaks. Each certificate must be in the following format:
-----BEGIN CERTIFICATE----- at the beginning -----END CERTIFICATE----- at the end-----BEGIN CERTIFICATE-----
xxxxxx1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
xxxxxx1
-----END CERTIFICATE-----
application_federated_credential_name
String
The name of the application's federated credential.
private_ca
Request example:
curl --request POST \ --url 'https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxx' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxx' \ --data-urlencode 'client_assertion=xxxxx' \ --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
The validity period, as a UNIX timestamp, in seconds.
expires_at
Long
No
The expiration time, as a UNIX timestamp, in seconds.
token_type
String
No
The access token type.
Response example:
{ "token_type": "Bearer", "access_token": "AT8csE2******HBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
Error codes
HttpCode | error | Error message | Description |
400 | invalid_request | Require parameter variable: grant_type | The request is missing a required parameter, contains an invalid parameter value, contains multiple parameters, or is 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 incorrect. Supported authentication 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 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)
This appendix provides a complete example of generating a JWT (JSON Web Token) signature in Java, using the RS256 asymmetric encryption algorithm. It includes:
Maven dependency configuration:
<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 key // Enter the application's client_id private static final String ISSUER = "your_client_id"; // Enter the application's client_id private static final String SUBJECT = "your_client_id"; // Enter the token endpoint of the 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 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 token:"); 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 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 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)
This appendix provides a complete example of generating a JWT (JSON Web Token) signature in Java, using the HS256 signature algorithm. The example includes:
Maven dependency configuration:
<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 key // Enter the application's client_id private static final String ISSUER = "your_client_id"; // Enter the application's client_id private static final String SUBJECT = "your_client_id"; // Enter the token endpoint of the 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 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 JWT String jwt = generateJwt(); System.out.println("Generated JWT: " + jwt); } }