Check and Refresh IBM Cloud Access Tokens with PHP

To access an IBM Cloud service instance, you must have an IAM access token. To obtain an IAM access token, you must have an API key for the service.

Access tokens can be obtained directly from the IBM Cloud IAM service, by making an HTTP query to the API endpoint at https://iam.cloud.ibm.com/identity/token and including an API key in the request. Here’s an example:

curl -X POST 'https://iam.cloud.ibm.com/identity/token' -H 'Content-Type: application/x-www-form-urlencoded' -d 'grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey=YOUR-API-KEY-HERE'

However, these access tokens are short-lived – typically, they expire after 60 minutes and need to be renewed after that expiry period.

An application which relies on consistent access to one or more IBM Cloud services will therefore need additional business logic to periodically check and renew its IBM Cloud access tokens. Here’s an example of a function I wrote to perform this task for a PHP Web application:


<?php
// load required classes
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;

function getAccessToken($apiKey, $tokenFile) {

    $tokenConfig = include($tokenFile);

    $secret = 'YOUR-HARD-TO-GUESS-RANDOM-KEY';

    if (empty($tokenConfig) || Crypto::decryptWithPassword($tokenConfig['apikey'], $secret) !== $apiKey || $tokenConfig['expiration'] < time()) {
        $client = new \GuzzleHttp\Client();
        $response = $client->request(
            'POST', 
            'https://iam.cloud.ibm.com/identity/token',
            [
                'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
                'body' => 'grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey=' . $apiKey
            ]
        );
        $data = json_decode($response->getBody()->getContents());
        $tokenConfig = [
            'token' => Crypto::encryptWithPassword($data->access_token, $secret),
            'apikey' => Crypto::encryptWithPassword($apiKey, $secret),
            'expiration' => $data->expiration
        ];
    
        file_put_contents($tokenFile, '<?php return ' . var_export($tokenConfig, true) . ';');    
    }

    return Crypto::decryptWithPassword($tokenConfig['token'], $secret);
}

This function uses two packages: Guzzle to perform the HTTP request to the IBM Cloud IAM service and Defuse to encrypt and decrypt the application’s IBM Cloud access token (transient) and API key (static). These two credentials, together with the token’s expiration timestamp, are stored in a secure configuration file on disk.

On invocation, the function first checks the specified configuration file to see if an encrypted token exists for the specified API key and if so, its expiry date. If the token is valid, it decrypts and returns the token to the caller. If no token exists, or if the token has expired, it uses the API key to request a new token from the IBM Cloud IAM service, encrypts both with a secret and saves them to the configuration file, together with the new expiration timestamp.

This function can be invoked in application code wherever an access token is required as follows:


<?php
// ...
$token = getAccessToken('YOUR-API-KEY-HERE', 'YOUR-CONFIG-FILE-HERE');