All Products
Search
Document Center

Identity as a Service:M2M client token call examples

Last Updated:Nov 13, 2025

This document provides examples of machine-to-machine (M2M) client token calls in Alibaba Cloud IDaaS (EIAM). It explains how to obtain an access token using the OAuth 2.0 client credentials flow and call an API for secure system-to-system authentication.

Call examples

Authentication method: client_secret_basic

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Authorization

    String

    The value of this parameter is the Base64-encoded string of the clientId and clientSecret, merged in the format clientId:clientSecret.

    YXBwX201ZG9vemVzbm81Mmtxxxxxxxxx

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is as follows: api://api.xxxxx.com|read:file

    You can obtain all authorized scopes using {resourceServerIdentifier}|.all.

    api://api.xxxxx.com|read:file

    client_id

    string

    The application ID.

  4. 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'
  5. Response parameters

    Parameter

    Type

    Optional

    Description

    access_token

    String

    No

    The token value.

    expires_in

    Long

    No

    The expiration duration in seconds.

    expires_at

    Long

    No.

    The expiration time. This is a UNIX timestamp in seconds.

    token_type

    String

    No, it is not.

    The token type.

  6. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: client_secret_post

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_secret

    String

    The application secret.

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is as follows: api://api.xxxxx.com|read:file

    You can obtain all authorized scopes for the current client using {resourceServerIdentifier}|.all.

    api://api.xxxxx.com|read:file

  4. 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'
  5. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: client_secret_jwt

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_assertion_type

    String

    The client assertion type. Static field: urn:ietf:params:oauth:client-assertion-type:jwt-bearer.

    client_assertion

    String

    The signature issued by the client using the client_secret. The signature is in JWT format and uses the HS256 algorithm. For more information, see Appendix 2.

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is: api://api.xxxxx.com|read:file

    You can obtain all authorized scopes using {resourceServerIdentifier}|.all.

    api://api.xxxxx.com|read:file

  4. 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'
  5. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: private_key_jwt

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_assertion_type

    String

    The client assertion type. Static field: urn:ietf:params:oauth:client-assertion-type:jwt-bearer.

    client_assertion

    String

    The signature issued by the client using the private key. The signature is in JWT format and uses the RS256 algorithm. For more information, see Appendix 1.

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is: api://api.xxxxx.com|read:file

    You can obtain all scopes authorized for the current client using {resourceServerIdentifier}|.all.

    api://api.xxxxx.com|read:file

  4. 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'
  5. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: OIDC federated authentication

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_assertion_type

    String

    The client assertion type. Static field: 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

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final output is: api://api.xxxxx.com|read:file

    To obtain all scopes 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

  4. 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'
  5. Response parameters

    Parameter

    Type

    Optional

    Description

    access_token

    String

    No

    The access token value.

    expires_in

    Long

    No

    The expiration duration in seconds.

    expires_at

    Long

    No, it is not.

    The expiration time. This is a UNIX timestamp in seconds.

    token_type

    String

    No, it is not.

    The access token type.

  6. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: PKCS#7 signature authentication

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_assertion_type

    String

    The client assertion type. Static field: urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer.

    client_assertion

    String

    The PKCS#7 signature value.

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is as follows: api://api.xxxxx.com|read:file

    You can obtain all authorized scopes using {resourceServerIdentifier}|.all.

    api://api.xxxxx.com|read:file

    application_federated_credential_name

    String

    The name of the application's federated credential.

    aliyun_ecs

  4. 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
  5. Response parameters

    Parameter

    Type

    Nullable

    Description

    access_token

    String

    No, it is not.

    The access token value.

    expires_in

    Long

    No

    The expiration duration in seconds.

    expires_at

    Long

    No, it is not.

    The expiration time. This is a UNIX timestamp in seconds.

    token_type

    String

    No, it is not.

    The access token type.

  6. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Authentication method: Private CA certificate authentication

  1. Request method: POST

  2. Header parameters

    Parameter

    Type

    Description

    Example

    Content-Type

    String

    Static field: application/x-www-form-urlencoded.

    application/x-www-form-urlencoded

  3. Request parameters

    Parameter

    Type

    Description

    Example

    grant_type

    String

    Static field: client_credentials.

    client_credentials

    client_id

    String

    The application ID.

    client_assertion_type

    String

    The client assertion type. Static field: urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer.

    client_assertion

    String

    The JWT token issued by the client using the private_key.

    scope

    String

    Request permissions based on the scope. The value is a space-separated string. The format for each permission is resourceServerIdentifier|scope. For example:

    The resourceServerIdentifier is api://api.xxxxx.com, and the scope is read:file.

    The final result is: api://api.xxxxx.com|read:file.

    To obtain all scopes that have been granted to the current client, use:

    api://api.xxxxx.com|read:file

    client_x509

    String

    The end-entity certificate (leaf certificate), which is the client certificate.

    Base64-encoded Distinguished Encoding Rules (DER)

    -----BEGIN CERTIFICATE-----

    xxxxxx

    -----END CERTIFICATE-----

    client_x509_chain

    String

    A list of intermediate certificates (Intermediate CA).

    They must be Base64-encoded strings in DER format.

    Concatenate multiple certificates using line breaks. Each certificate must be in the following format:

    -----BEGIN CERTIFICATE-----start
    -----END CERTIFICATE-----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

  4. 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'
  5. Response parameters

    Parameter

    Type

    Optional

    Description

    access_token

    String

    No.

    The access token value.

    expires_in

    Long

    No, it is not.

    The expiration duration in seconds.

    expires_at

    Long

    No

    The expiration time. This is a UNIX timestamp in seconds.

    token_type

    String

    No, it is not.

    The access token type.

  6. Response example

    {
      "token_type": "Bearer",
      "access_token": "AT8csE2sepE4TT9j45xFgRGhEDyS3ovfZDF68Ac4aaQ7c4dBpUahD1cYSCFQbsfpM9ysSArv1pTszcGTZEJK11yGA62GKWd4cf33ZVGsgPfLwYDPX2ZRCUpThTaWoxtXCs9zeZzGwxjc5xtasaQMeuE8PuGeHg9SyMzKxJQVv9ubQhoFXjQkoPUotUms4R2M9SBLpWSCaGDf3oiJ5WCuGyMzJdrrdQeLSB7dU9P1iKbjxGWCmwaMLMkUWZBKsAeYi3xjJmpMsuLq3811KAV5bttwi8z8cafuweuNvwdjfZYCYvNbRAt1nB9Bxn9Q99rdpYawU3eH3UvzkvMYoJ5wtnGSsPJ9B7NHBkxxHUG",
      "expires_in": 3600,
      "expires_at": 1733710213
    }

Error codes

HTTP Code

Error

Error message

Description

400

invalid_request

Require parameter variable: grant_type

The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or 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 incorrect. Supported authentication methods are:

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 how to generate a JSON Web Token (JWT) signature using Java with the RS256 asymmetric key encryption algorithm. It includes the following:

  1. 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>
  2. 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;
    
    /**
     * @author fei.chen
     * @date 2025-02-24 16:17
     */
    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;
    
    /**
     * @author fei.chen
     * @date 2025-02-24 16:51
     */
    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)

This appendix provides a complete example of how to generate a JSON Web Token (JWT) signature using Java with the HS256 signature algorithm. The example includes the following:

  1. 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>
  2. 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);
        }
    }