skip to main content

Sample Java source code

The Java source code below shows how to obtain an access token from Social Security OAuth server.

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GetAccessToken {
    private static final Logger logger = Logger.getLogger(GetAccessToken.class.getName());
    /**
     * Main method to generate an OAuth 2.0 token using client credentials grant.
     * To run this program, provide the path to a properties file as a command line argument.
     * The properties file should contain the following keys (and be adjusted accordingly to your environment)
     * audience=https://services.socialsecurity.be/REST/oauth/v5/token
     * authUrl=https://services.socialsecurity.be/REST/oauth/v5/token
     * clientId=self_service_chaman_xxxxxxxxxxxxxxxx  // replace with your client ID
     * scope=scope:rsz-onss:socialdebt:retention:billretainment-rest:post-billretainment
     * password=your-key-store-password // replace with your keystore password
     * certificate=path-to-your-PKCS12-file // replace with the path to your PKCS12 file
     * keyAlias=your key alias // replace with your key alias
     *
     * @param args Command line arguments should include the path to the properties file.
     */
    public static void main(String[] args) {
        Properties prop = new Properties();
        try (FileInputStream fis = new FileInputStream(args[0])) {
            prop.load(fis);
        } catch (IOException e) {
            logger.log(Level.SEVERE, e.getMessage(), e);
            return;
        }
        // Extract necessary properties for OAuth token request
        String audience = prop.getProperty("audience");
        String authUrl = prop.getProperty("authUrl");
        String clientId = prop.getProperty("clientId");
        String scope = prop.getProperty("scope");
        String password = prop.getProperty("password");
        String certificate = prop.getProperty("certificate");
        String keyAlias = prop.getProperty("keyAlias");
        try {
            // Generate and print the access token
            String accessTokenResponse = getAccessToken(certificate, password, keyAlias, audience, clientId, authUrl, scope);
            logger.log(Level.INFO, accessTokenResponse);
        } catch (Exception ex) {
            logger.log(Level.SEVERE,ex.getMessage(), ex);
        }
    }
    /**
     * Retrieves the access token using the provided parameters.
     *
     * @param certificate Path to the certificate file.
     * @param password Certificate's password.
     * @param keyAlias Alias of the private key within the certificate.
     * @param audience Token endpoint audience.
     * @param clientId Client ID for OAuth.
     * @param authUrl Authorization server URL.
     * @param scope OAuth scopes requested.
     * @return A string containing the access token.
     * @throws IOException If an I/O error occurs during communication with the OAuth server.
     * @throws GeneralSecurityException If there is an issue with the private key or signature.
     * @throws URISyntaxException If the URI is invalid.
     */
    private static String getAccessToken(String certificate, String password, String keyAlias, String audience, String clientId, String authUrl, String scope)
            throws IOException, GeneralSecurityException, URISyntaxException {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        PrivateKey privateKey;
        // Load the keystore and extract the private key
        try (FileInputStream fis = new FileInputStream(certificate)) {
            keyStore.load(fis, password.toCharArray());
            privateKey = (PrivateKey) keyStore.getKey(keyAlias, password.toCharArray());
        }
        // Create a signed JWT for the OAuth authentication request
        String jwt = createJWT(privateKey, clientId, audience);
        // Send the JWT to the OAuth server and retrieve the access token
        return doPostToAuthServer(jwt, new URI(authUrl), scope);
    }
    /**
     * Creates a signed JWT for the OAuth authentication request.
     *
     * @param privateKey The private key used to sign the JWT.
     * @param clientId The OAuth client ID.
     * @param audience The audience for the token, usually the token URL.
     * @return A signed JWT string.
     * @throws NoSuchAlgorithmException If the RSA algorithm is not supported.
     * @throws InvalidKeyException If the private key is invalid.
     * @throws SignatureException If there is an issue with the signature.
     * @throws InvalidKeyException If the private key is invalid.
     */
    private static String createJWT(PrivateKey privateKey, String clientId, String audience) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        long nowMillis = System.currentTimeMillis(); // Current time in milliseconds
        long expMillis = nowMillis + 3600000; // JWT validity for 1 hour
        String jti = UUID.randomUUID().toString(); // Unique identifier for each JWT
        // Create the JWT header and payload
        String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; // JWT header
        String payload = String.format(
                "{\"iss\":\"%s\",\"sub\":\"%s\",\"aud\":\"%s\",\"exp\":%d,\"iat\":%d,\"jti\":\"%s\"}",
                clientId, clientId, audience, expMillis / 1000, nowMillis / 1000, jti);
        // Encode the header and payload
        String encodedHeader = Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes(StandardCharsets.UTF_8));
        String encodedPayload = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.getBytes(StandardCharsets.UTF_8));
        // Concatenate the encoded header and payload
        String assertion = encodedHeader + "." + encodedPayload;
        // Sign the JWT using the RS256 algorithm
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(assertion.getBytes(StandardCharsets.UTF_8));
        byte[] signedAssertion = signature.sign();
        // Encode the signature and append it to the assertion to create the final JWT
        String encodedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signedAssertion);
        return assertion + "." + encodedSignature;
    }
    /**
     * Sends a POST request to the OAuth server and retrieves the access token.
     *
     * @param jwt The JWT used for client assertion.
     * @param authUri The URI of the OAuth server.
     * @param scope The requested scope(s).
     * @return The access token as a String.
     * @throws IOException If an I/O error occurs during communication with the OAuth server.
     */
    private static String doPostToAuthServer(String jwt, URI authUri, String scope) throws IOException {
        // Create a connection to the OAuth server
        URL url = new URL(authUri.toString());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setDoOutput(true);
        // Construct the request parameters
        String params = String.format("grant_type=%s&client_assertion_type=%s&client_assertion=%s&scope=%s",
                "client_credentials", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", jwt, scope);
        // Send the request and read the response
        try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
            wr.writeBytes(params);
            wr.flush();
        }
        // Read the response from the server
        StringBuilder response = new StringBuilder();
        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
                reader.lines().forEach(response::append);
            }
        } else {
            // Read the error stream to capture any error messages from the server
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
                reader.lines().forEach(response::append);
            }
        }
        return response.toString();
    }
}