Rubrik
  • Products
  • Solutions
  • Knowledge Hub
  • About Us
  • CXO
  • Partners
  • Support
  • Contact Sales
Rubrik
LinkedInTwitterFacebookYouTubeInstagram

Call us at 1-844-478-2745

Submit Interest

ABOUT RUBRIK

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog

NEW TO RUBRIK

Why RubrikProductsSolutionsPartnersCustomersResources

POPULAR LINKS

Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog
Why RubrikProductsSolutionsPartnersCustomersResources
Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups

CompanyLeadershipInvestor RelationsNewsroom & Press ReleasesCareersBlog
Why RubrikProductsSolutionsPartnersCustomersResources
Cyber RecoveryBackup & RecoveryRansomware Recovery Cloud Disaster RecoveryCloud Database Backup and Recovery ServiceSaaS Backups
  • Cookie Policy
  • Legal
  • Privacy Policy
  • Terms of Use
  • Trust
  • CA Residents only: Do not sell or share my personal information | Do not share my sensitive information

© 2026 Rubrik – Zero Trust Data Security™

Technical Blog Hub

Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken

TutorialServicesAPI-First Automation
MAY 13, 20266 min read
TutorialServicesAPI-First Automation
MAY 13, 20266 min read
Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken
Share
Background
Technical Blog Hub

Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken

TutorialServicesAPI-First Automation
MAY 13, 20266 min read
TutorialServicesAPI-First Automation
MAY 13, 20266 min read
Talking to Rubrik Security Cloud: PHP Authentication with rkRscGetToken
Share

Table of Contents

Introduction

In Week 1, we announced the reboot of the PHP framework and laid out the 12-week roadmap. In Week 2, we explored how GraphQL works in Rubrik Security Cloud (RSC) - from queries and mutations to the Connection -> Node pattern that powers the API.

Now it's time to make things real.

Before we can send a single GraphQL query from PHP, our code needs to authenticate to RSC and obtain a Bearer token using client credentials (OAuth2). Authentication isn't glamorous, but it is foundational, and doing it right from the start means every function we build on top of it will be portable, secure, and production-ready.

This week covers three essential pieces: how RSC authentication works, how to store your secrets safely, and how to encapsulate all of it into a reusable PHP helper - rkRscGetToken().

How Authentication Works in RSC

Rubrik Security Cloud uses the OAuth2 Client Credentials flow when authenticating programmatically via a Service Account.

To create one, navigate to:

Settings -> Users and Access -> Service Accounts

When you create a Service Account, RSC provides three pieces of information:

  • Client ID (format: client|xxxxxxxx-xxxx-...)
  • Client Secret (a random string - treat it like a password)
  • Access Token URI (https://<your-tenant>/api/client_token)

Important: The client secret is shown only once. If you lose it, you must generate a new one.

 

Practitioner Tip

"Always ensure you leverage least-privilege RBAC when scoping your service accounts. Give them access only to what they need within the script."

Your script must send the following to the token endpoint:

  • client_id
  • client_secret
  • grant_type=client_credentials

To: https://<your-tenant>/api/client_token

The endpoint returns an access_token (used in Authorization: Bearer <token>) and expires_in (lifetime in seconds). Best practice: cache the token until it expires - there's no reason to re-authenticate on every API call.

 

Practitioner Tip

"If authentication feels abstract, don't overthink it - it's just a simple HTTP POST. Test it with curl first, understand the response, then automate it in code."

The Raw cURL Call

Before writing a single line of PHP, it helps to see the authentication request in its simplest form. Here is the equivalent curl request:

export RSC_FQDN="example.my.rubrik.com"
export RSC_CLIENT_ID="client|c9bba9a9-1234-1234-b7c6-123440b4cf64"
export RSC_CLIENT_SECRET="ExampleServiceAccountSecret"

curl --silent --location "https://$RSC_FQDN/api/client_token" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data "client_id=$RSC_CLIENT_ID&client_secret=$RSC_CLIENT_SECRET&grant_type=client_credentials"

A successful response looks like this:

{
  "client_id": "client|c9bba9a9-1234-1234-b7c6-123560b4cf64",
  "access_token": "eyJ...",
  "expires_in": 43200
}

Our PHP function will perform exactly this call under the hood.

Storing the Client ID and Secret Safely

Your client_id and client_secret are the keys to your RSC environment. They carry the same weight as a password and should be treated accordingly.

Three rules to build around:

  • Secrets in source code are a liability that outlives your tenure. Version control is forever - a credential committed today can be extracted from git history long after it has been deleted.
  • Runtime-injected secrets are invisible to the artifact; hardcoded ones travel with it. Into every registry push, every backup, every build log.
  • Credentials that live in one place outside of code can be rotated in seconds, not hours. That gap matters when you are mid-incident.

The cleanest way to do this is environment variables - available at runtime, invisible to source control, and straightforward to rotate without touching application logic.

Option A - Interactive Usage (Good for Testing)

export RSC_FQDN="example.my.rubrik.com"
export RSC_CLIENT_ID="client|xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export RSC_CLIENT_SECRET="yourServiceAccountSecret"
php ./scripts/get_token.php

These variables live in the execution environment for the duration of your session and are available to any script running in that context - interactive shells, scheduled jobs, containers, automation platforms.

Option B - Secrets File

Create a file called rsc_secrets.env and store it in a hidden folder. Since the credentials in this file sit in plain text on your machine, consider using a vault or password manager.

export RSC_FQDN="example.my.rubrik.com"
export RSC_CLIENT_ID="client|xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
export RSC_CLIENT_SECRET="yourServiceAccountSecret"

# Optional settings
export RSC_VERIFY_SSL="true"
export RSC_HTTP_TIMEOUT="30"
export RSC_TOKEN_CACHE="./.rsc_token_cache.json"

Load and Run:

source ./rsc_secrets.env
php ./scripts/get_token.php

This keeps secrets out of your code, centralised, and easy to rotate.

 

Practitioner Tip

"If your script needs credentials hardcoded to work, you're doing it wrong. Your code should run unchanged whether it's on your laptop, a server, or a pipeline."

Option C - Automation / Production (Recommended)

In production environments, use a secret manager and inject environment variables at runtime. Keep PHP unchanged - your code always reads the same way:

getenv('RSC_CLIENT_SECRET');

What "Secure" Means in Practice

Getting the code right is only half the job. The other half is operational discipline - and this is where most real-world credential incidents actually originate.

  • Treat your logs as an attack surface. Debug output, HTTP traces, and error logs can silently leak tokens - audit what gets captured before you ship to production.
  • Apply least-privilege permissions to every secrets file. chmod 600 on rsc_secrets.env and a .gitignore entry are non-negotiable - one accidental commit can expose credentials in perpetuity.
  • Build credential rotation into your operational runbook, not your compliance checklist. If you have never practiced revoke-and-redeploy under pressure, your recovery plan is theoretical.
  • Keep secrets out of your artifacts entirely. Credentials baked into images travel through registries, backups, and pipelines - runtime injection means a leaked image does not mean a leaked credential.

Designing rkRscGetToken()

With the authentication flow understood and our secrets strategy in place, we can now build the helper function. The design goal is deliberately simple:

$token = rkRscGetToken();

One call. No parameters. The function handles everything else. Specifically, it should:

  • Read configuration from environment variables (no parameters required)
  • Use local token caching to avoid redundant API calls
  • Throw clear, actionable exceptions on failure
  • Work identically across local development, CI pipelines, and production environments

Implementation: rkRscGetToken()

Create the file rkRscAuth.php:

<?php

function rkRscGetToken(): string
{
    // ------------------------------------------------------------
    // 1) Required environment variables
    // ------------------------------------------------------------
    $fqdn         = getenv('RSC_FQDN') ?: '';
    $clientId     = getenv('RSC_CLIENT_ID') ?: '';
    $clientSecret = getenv('RSC_CLIENT_SECRET') ?: '';

    if ($fqdn === '')
    {
        throw new Exception("Missing RSC_FQDN");
    }
    if ($clientId === '')
    {
        throw new Exception("Missing RSC_CLIENT_ID");
    }
    if ($clientSecret === '')
    {
        throw new Exception("Missing RSC_CLIENT_SECRET");
    }

    // ------------------------------------------------------------
    // 2) Optional settings
    // ------------------------------------------------------------
    $cacheFile = getenv('RSC_TOKEN_CACHE');
    if ($cacheFile === false || $cacheFile === '')
    {
        $cacheFile = __DIR__ . '/.rsc_token_cache.json';
    }

    $verifySsl    = true;
    $verifySslEnv = getenv('RSC_VERIFY_SSL');
    if ($verifySslEnv !== false && $verifySslEnv !== '')
    {
        $parsed    = filter_var($verifySslEnv, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        $verifySsl = ($parsed === null) ? true : $parsed;
    }

    $timeout    = 30;
    $timeoutEnv = getenv('RSC_HTTP_TIMEOUT');
    if ($timeoutEnv !== false && is_numeric($timeoutEnv))
    {
        $timeout = (int)$timeoutEnv;
    }

    // ------------------------------------------------------------
    // 3) Token cache
    // ------------------------------------------------------------
    if (file_exists($cacheFile))
    {
        $raw = file_get_contents($cacheFile);
        if ($raw !== false)
        {
            $cached = json_decode($raw, true);
            if (isset($cached['access_token'], $cached['expires_at']))
            {
                if ((int)$cached['expires_at'] > (time() + 60))
                {
                    return (string)$cached['access_token'];
                }
            }
        }
    }

    // ------------------------------------------------------------
    // 4) Request token
    // ------------------------------------------------------------
    $url  = "https://{$fqdn}/api/client_token";

    $post = http_build_query(
        [
            'client_id'      => $clientId,
            'client_secret' => $clientSecret,
            'grant_type'    => 'client_credentials',
        ]
    );

    $ch = curl_init();
    if ($ch === false)
    {
        throw new Exception("Failed to initialize cURL");
    }
    curl_setopt_array(
        $ch,
        [
            CURLOPT_URL            => $url,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $post,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/x-www-form-urlencoded',
            ],
            CURLOPT_TIMEOUT        => $timeout,
        ]
    );

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifySsl);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifySsl ? 2 : 0);

    $responseBody = curl_exec($ch);

    if ($responseBody === false)
    {
        throw new Exception("cURL error: " . curl_error($ch));
    }

    $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if ($httpCode < 200 || $httpCode >= 300)
    {
        throw new Exception("HTTP {$httpCode}: {$responseBody}");
    }

    // curl_close() not used (deprecated in PHP 8.5+)

    // ------------------------------------------------------------
    // 5) Parse response
    // ------------------------------------------------------------
    $data = json_decode($responseBody, true);

    if (!is_array($data) || empty($data['access_token']))
    {
        throw new Exception("Invalid token response");
    }

    $accessToken = (string)$data['access_token'];
    $expiresAt   = time() + ((int)$data['expires_in'] ?? 3600);

    // ------------------------------------------------------------
    // 6) Cache token
    // ------------------------------------------------------------
    file_put_contents(
        $cacheFile,
        json_encode(
            [
                'access_token' => $accessToken,
                'expires_at'   => $expiresAt,
            ],
            JSON_PRETTY_PRINT
        )
    );

    return $accessToken;
}

Minimal Validation Script

With rkRscAuth.php in place, verifying that authentication works takes just a handful of lines. Create scripts/get_token.php:

<?php
require_once __DIR__ . '/../rkRscAuth.php';

try
{
    $token = rkRscGetToken();
    echo "Token retrieved successfully (" . strlen($token) . " characters)\n";
}
catch (Exception $e)
{
    echo "[ERROR] " . $e->getMessage() . "\n";
    exit(1);
}

Run it:

source ./rsc_secrets.env
php ./scripts/get_token.php
 

Practitioner Tip

"f your authentication code is longer than your business logic, you should probably refactor it into a helper - like we just did."

What We Achieved

With rkRscGetToken() complete, the authentication layer is done and out of the way. What we have now:

  • No credentials in code means no credential exposure in version control, container images, or build artifacts - the risk surface shrinks immediately
  • Token caching means your framework can call rkRscGetToken() freely without worrying about rate limits or unnecessary latency on every operation.
  • Exceptions that name the missing variable exactly tell you what is wrong and where, without digging through stack traces at 2am.
  • One function, zero environment-specific branches - the same code runs on a developer laptop, a CI runner, and a production scheduler without modification.

What's Next: Sending Your First Real Query

Authentication is done. Next week, we put it to work.

In Week 4, we will:

  • Build rkGraphQLFramework.php
  • Wrap GraphQL queries into reusable functions
  • Run our first real RSC queries using this token

Next step: real data.

Contributed by

Frederic Lhoest
Frederic Lhoest

Senior Technology Architect, PCCW Global

Frederic is an automation expert and veteran architect with over 25 years of experience in streamlining data center operations and seamless workflows. He is a VMware and Nutanix AHV expert, with a proven track record of turning complex operational obstacles into efficient, automated systems. Beyond his technical role, he is a prominent speaker and leader in the Rubrik practitioner community, dedicated to fostering collaborative environments where real-world challenges meet innovative solutions.
Mike Preston
Mike Preston

Staff Technical Marketing Manager, Rubrik

Mike Preston is a Staff Technical Marketing Architect at Rubrik, leading the charge in all things Cloud and Automation. With an education focused on software engineering and over 25 years of IT operations experience, Mike strives to bridge the gap between development and operations — automating processes and streamlining workflows. He is the Toronto VMUG leader, author of Troubleshooting vSphere Storage, and an overall believer in sharing the knowledge!

Related Blogs

View all Posts
Reviving the Rubrik PHP Framework: The GraphQL Rebirth
Tutorial
APR 30, 2026

Reviving the Rubrik PHP Framework: The GraphQL Rebirth

Transition from REST to GraphQL with Rubrik Security Cloud. Explore a 12-week roadmap to build compliance dashboards, recovery portals, and advanced automation tools.

4 min read

Frederic Lhoest

Frederic Lhoest

Senior Technology Architect

PCCW Global

GraphQL 101 for Rubrik Security Cloud
Tutorial
APR 30, 2026

GraphQL 101 for Rubrik Security Cloud

Master GraphQL for Rubrik Security Cloud. Learn query vs. mutation patterns, the Connection-Node model, and expert tips for using the RSC API Playground and DevTools.

5 min read

Frederic Lhoest

Frederic Lhoest

Senior Technology Architect

PCCW Global

View all Posts

Share Your Insights

Have an interesting story or technical findings to share? Reach out to create a blog with us.

Learning & Certifications

Access free and instructor-led training and certification paths to master Rubrik products and maximise your data security expertise.

Explore coursesNext
Background

Share Your Insights

Have an interesting story or technical findings to share? Reach out to create a blog with us.

Learning & Certifications

Access free and instructor-led training and certification paths to master Rubrik products and maximise your data security expertise.

Explore coursesNext