PHP

OAuth 2.0 Client Credentials Grant for API Access

Learn to securely obtain an access token using the OAuth 2.0 Client Credentials grant type for server-to-server API authentication with Guzzle HTTP client in PHP.

<?php

require 'vendor/autoload.php'; // Assuming you use Composer to manage dependencies (e.g., guzzlehttp/guzzle)

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class OAuthClientCredentials
{
    private $tokenUrl;
    private $clientId;
    private $clientSecret;
    private $scope;
    private $httpClient;
    private $accessToken = null;
    private $expiresAt = 0;

    public function __construct(string $tokenUrl, string $clientId, string $clientSecret, string $scope = '')
    {
        $this->tokenUrl = $tokenUrl;
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->scope = $scope;
        $this->httpClient = new Client();
    }

    /**
     * Obtains an access token using the Client Credentials Grant.
     * Caches the token and refreshes if expired.
     *
     * @return string The access token.
     * @throws GuzzleException If token request fails.
     * @throws \Exception If token data is invalid.
     */
    public function getAccessToken(): string
    {
        if ($this->accessToken && $this->expiresAt > time() + 60) { // Refresh 60 seconds before actual expiry
            return $this->accessToken;
        }

        try {
            $response = $this->httpClient->post($this->tokenUrl, [
                'form_params' => [
                    'grant_type' => 'client_credentials',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'scope' => $this->scope,
                ],
                'headers' => [
                    'Accept' => 'application/json',
                ],
            ]);

            $data = json_decode($response->getBody()->getContents(), true);

            if (!isset($data['access_token']) || !isset($data['expires_in'])) {
                throw new \Exception('Invalid token response from server.');
            }

            $this->accessToken = $data['access_token'];
            $this->expiresAt = time() + $data['expires_in'];

            return $this->accessToken;

        } catch (GuzzleException $e) {
            error_log("Failed to obtain OAuth access token: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Make an authenticated API request.
     *
     * @param string $method HTTP method (GET, POST, etc.)
     * @param string $url The full URL for the API request.
     * @param array $options Guzzle request options.
     * @return \Psr\Http\Message\ResponseInterface
     * @throws GuzzleException
     */
    public function makeAuthenticatedRequest(string $method, string $url, array $options = []): \Psr\Http\Message\ResponseInterface
    {
        $token = $this->getAccessToken();
        $options['headers']['Authorization'] = 'Bearer ' . $token;

        return $this->httpClient->request($method, $url, $options);
    }
}

// Example Usage:
// $tokenUrl = 'https://auth.example.com/oauth/token';
// $clientId = 'your_client_id';
// $clientSecret = 'your_client_secret';
// $scope = 'read write'; // Optional scopes

// try {
//     $oauthClient = new OAuthClientCredentials($tokenUrl, $clientId, $clientSecret, $scope);

//     // Get an access token
//     // $accessToken = $oauthClient->getAccessToken();
//     // echo "Access Token: " . $accessToken . "
";

//     // Make an authenticated API request
//     $apiResponse = $oauthClient->makeAuthenticatedRequest('GET', 'https://api.example.com/data');
//     echo "API Response: " . $apiResponse->getBody()->getContents() . "
";

// } catch (GuzzleException $e) {
//     echo "API or OAuth error: " . $e->getMessage() . "
";
// } catch (\Exception $e) {
//     echo "General error: " . $e->getMessage() . "
";
// }
How it works: This PHP snippet demonstrates how to implement the OAuth 2.0 Client Credentials grant flow using Guzzle HTTP client. It encapsulates the logic for requesting an access token from an authorization server using a client ID and secret. The token is cached and automatically refreshed before expiry, allowing subsequent API requests to be made with a valid `Bearer` token in the `Authorization` header, suitable for server-to-server communication.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs