All Products
Search
Document Center

Identity as a Service:M2M client token call examples

Last Updated:Mar 31, 2026

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.

MethodCredential typeSecurity levelUse when
client_secret_basicShared secret (HTTP Basic)StandardSimple integrations where the secret is sent in the Authorization header
client_secret_postShared secret (request body)StandardClients that cannot set custom headers
client_secret_jwtShared secret, JWT-signed (HS256)HigherYou want to avoid transmitting the raw secret on the wire
private_key_jwtRSA private key, JWT-signed (RS256)HighestProduction systems requiring asymmetric key security
OIDC federated authenticationExternal OIDC tokenHighYour service already holds an OIDC token from an identity provider (e.g., Alibaba Cloud ACK)
PKCS#7 signature authenticationPKCS#7 signatureHighYour system generates PKCS#7 signatures (e.g., hardware security modules)
Private CA certificate authenticationX.509 client certificateHighYour 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/token

Authentication methods

client_secret_basic

Encode the client_id and client_secret as a Base64 string and pass it in the Authorization header.

Header parameters

ParameterTypeRequiredDescriptionExample
AuthorizationStringYesBasic followed by the Base64-encoded string of <client_id>:<client_secret>Basic YXBwX201ZG9vemVzbm81Mmtxxxxxxxxx
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
scopeStringYesSpace-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_idStringYesThe application IDapp_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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application IDapp_m5doozesno52kbqrqpw3xxxx
client_secretStringYesThe application secretCS5v3F4Cy8hyDmFPJtAuyHDTUdR8i88GcgcXXXXX
scopeStringYesSpace-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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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`

ClaimDescriptionValue
issIssuerYour client_id
subSubjectYour client_id
audAudienceThe token endpoint URL
expExpirationMust not exceed 30 minutes from issuance
jtiJWT IDA unique UUID per request (anti-replay)

Header parameters

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application ID
client_assertion_typeStringYesAlways urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertionStringYesThe JWT signed with the client_secret using HS256
scopeStringYesSpace-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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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`

ClaimDescriptionValue
issIssuerYour client_id
subSubjectYour client_id
audAudienceThe token endpoint URL
expExpirationMust not exceed 30 minutes from issuance
jtiJWT IDA unique UUID per request (anti-replay)

Header parameters

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application ID
client_assertion_typeStringYesAlways urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertionStringYesThe JWT signed with the RSA private key using RS256
scopeStringYesSpace-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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application ID
client_assertion_typeStringYesAlways urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer
client_assertionStringYesThe OIDC token in JWT format
scopeStringYesSpace-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_nameStringYesThe name of the application's federated credentialaliyun_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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application ID
client_assertion_typeStringYesAlways urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer
client_assertionStringYesThe PKCS#7 signature value
scopeStringYesSpace-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_nameStringYesThe name of the application's federated credentialaliyun_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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways 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

ParameterTypeRequiredDescriptionExample
Content-TypeStringYesAlways application/x-www-form-urlencodedapplication/x-www-form-urlencoded

Request parameters

ParameterTypeRequiredDescriptionExample
grant_typeStringYesAlways client_credentialsclient_credentials
client_idStringYesThe application ID
client_assertion_typeStringYesAlways urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer
client_assertionStringYesA JWT issued by the client using the private key
scopeStringYesSpace-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_x509StringYesThe end-entity certificate (leaf certificate), Base64-encoded in DER format-----BEGIN CERTIFICATE-----xxxxxx-----END CERTIFICATE-----
client_x509_chainStringYesIntermediate 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_nameStringYesThe name of the application's federated credentialprivate_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

ParameterTypeNullableDescription
access_tokenStringNoThe access token value
expires_inLongNoToken lifetime in seconds
expires_atLongNoToken expiration as a UNIX timestamp in seconds
token_typeStringNoAlways Bearer

Response example

{
  "token_type": "Bearer",
  "access_token": "AT8csE2sepE******7NHBkxxHUG",
  "expires_in": 3600,
  "expires_at": 1733710213
}

Error codes

HTTP codeErrorError messageDescription
400invalid_requestRequire parameter variable: grant_typeA required parameter is missing, has an invalid value, appears more than once, or the request is otherwise malformed.
400authentication_requiredAuthentication 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.
400invalid_client_credentialInvalid client_assertion, reasons(s): [expired]The client_assertion is invalid. The token has expired.
400invalid_grantInvalid or not supported grant_type: authorization_codeThe grant_type value is not supported.
400invalid_scopeInvalid scope: http://www.example.com|read:fileThe requested scope is invalid, unknown, or malformed.
500internal_errorUnexpected internal errorAn 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);
    }
}