PHP code example of returnearly / laravel-cloudflare-zero-trust

1. Go to this page and download the library: Download returnearly/laravel-cloudflare-zero-trust library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

returnearly / laravel-cloudflare-zero-trust example snippets


use ReturnEarly\CloudflareZeroTrust\Enums\PrincipalKind;

'accounts' => [
    'acme' => [
        'team_domain' => 'https://acme.cloudflareaccess.com',
        'applications' => [
            'internal-api' => [
                'audience' => [env('CLOUDFLARE_INTERNAL_API_AUD')],
                'enabled' => (bool) env('CLOUDFLARE_INTERNAL_API_ENABLED', true),
                'principals' => [PrincipalKind::User, PrincipalKind::Service],
            ],
        ],
    ],
],

Route::middleware('cloudflare-access:internal-api')->group(function () {
    Route::get('/reports', ReportController::class);
});

use ReturnEarly\CloudflareZeroTrust\Support\Access;

Access::user()?->email();         // "[email protected]" for SSO users
Access::service()?->commonName(); // "my-worker.access" for service tokens

use ReturnEarly\CloudflareZeroTrust\Enums\PrincipalKind;

'accounts' => [
    'acme' => [
        // Your team domain. Also accepted under the key 'issuer'.
        'team_domain' => 'https://acme.cloudflareaccess.com',

        // Optional. Defaults to {team_domain}/cdn-cgi/access/certs
        // 'jwks_url' => 'https://acme.cloudflareaccess.com/cdn-cgi/access/certs',

        'applications' => [
            'internal-api' => [
                // One or more AUD tags. Also accepted under the key 'audiences'.
                'audience' => [env('CLOUDFLARE_INTERNAL_API_AUD')],

                // Optional. Prefer a per-app env var so you can disable enforcement
                // in local/staging without turning off every application.
                // When false, middleware passes through and the guard returns no user.
                'enabled' => (bool) env('CLOUDFLARE_INTERNAL_API_ENABLED', true),

                // Which principal kinds may authenticate.
                // Defaults to [PrincipalKind::User] — service tokens are opt-in.
                'principals' => [PrincipalKind::User, PrincipalKind::Service],

                // Optional. Set false to forbid identity enrichment for this app.
                'identity_enabled' => true,
            ],

            'horizon' => [
                'audience' => [env('CLOUDFLARE_HORIZON_AUD')],
                'enabled' => (bool) env('CLOUDFLARE_HORIZON_ENABLED', true),
                'principals' => [PrincipalKind::User], // humans only
            ],
        ],
    ],
],

Route::middleware('cloudflare-access:internal-api')->group(function () {
    // API endpoints reachable by SSO users and service tokens
});

Route::middleware('cloudflare-access:horizon')->group(function () {
    // Human-only admin surface
});

'middleware' => ['web', 'cloudflare-access:horizon'],

use ReturnEarly\CloudflareZeroTrust\Support\Access;

Access::token();          // ?VerifiedAccessToken — raw JWT, header, claims, expiry
Access::principal();      // ?Principal — UserPrincipal or ServicePrincipal
Access::user();           // ?UserPrincipal — null if this is a service request
Access::service();        // ?ServicePrincipal — null if this is a user request
Access::isUser();         // bool
Access::isService();      // bool
Access::commonName();     // ?string — the service token's client ID
Access::applicationIs('horizon'); // bool — which named application authenticated this request
Access::identity();       // ?AccessIdentity — lazy enrichment; throws on failure
Access::tryIdentity();    // ?AccessIdentity — null instead of throwing
Access::hasGroup('Finance-Team'); // bool — never throws

$user = Access::user();

$user->subject();       // stable Cloudflare user ID (JWT "sub")
$user->email();
$user->country();       // ?string, e.g. "US"
$user->accountName();   // config account name, e.g. "acme"
$user->applicationName();
$user->claims();        // full validated claim set

$service = Access::service();

$service->commonName();  // the service token client ID, e.g. "my-worker.access"
$service->claims();

'guards' => [
    'cloudflare' => [
        'driver' => 'cloudflare',
        'application' => 'internal-api',
    ],
],

Route::middleware('auth:cloudflare')->get('/me', function () {
    return auth('cloudflare')->user(); // UserPrincipal or ServicePrincipal
});

auth('cloudflare')->check();
auth('cloudflare')->id(); // user "sub" or service "common_name"

Route::middleware(['cloudflare-access:internal-api', 'auth:cloudflare'])->group(/* ... */);

use Illuminate\Contracts\Auth\Authenticatable;
use ReturnEarly\CloudflareZeroTrust\Contracts\ApplicationUserResolver;
use ReturnEarly\CloudflareZeroTrust\Principals\UserPrincipal;

class CloudflareUserResolver implements ApplicationUserResolver
{
    public function resolve(UserPrincipal $principal): ?Authenticatable
    {
        return User::firstWhere('email', $principal->email());
    }
}

'guards' => [
    'cloudflare' => [
        'driver' => 'cloudflare',
        'application' => 'internal-api',
        'resolver' => App\Auth\CloudflareUserResolver::class,
    ],
],

use ReturnEarly\CloudflareZeroTrust\Enums\PrincipalKind;

'internal-api' => [
    'audience' => [env('CLOUDFLARE_INTERNAL_API_AUD')],
    'principals' => [PrincipalKind::User, PrincipalKind::Service],
],

$identity = Access::identity(); // ?AccessIdentity

$identity->email;
$identity->userUuid;
$identity->geo;            // ?string
$identity->ip;             // ?string
$identity->groups;         // list<string> of IdP group names
$identity->idp;            // raw IdP payload
$identity->devicePosture;  // device posture checks
$identity->raw;            // the complete payload

Access::hasGroup('Finance-Team'); // convenience shortcut

use ReturnEarly\CloudflareZeroTrust\Events\AccessAuthenticationFailed;

Event::listen(function (AccessAuthenticationFailed $event) {
    Log::warning('Cloudflare Access rejected a request', [
        'reason' => $event->reasonCode,
        'application' => $event->application,
    ]);
});

use Firebase\JWT\JWT;
use Illuminate\Support\Facades\Http;

Http::fake([
    'https://acme.cloudflareaccess.com/cdn-cgi/access/certs' => Http::response([
        'keys' => [$publicJwk], // ['kty' => 'RSA', 'kid' => 'test-key', 'use' => 'sig', 'alg' => 'RS256', 'n' => ..., 'e' => ...]
    ]),
]);

$jwt = JWT::encode([
    'iss' => 'https://acme.cloudflareaccess.com',
    'aud' => ['your-aud-tag'],
    'type' => 'app',
    'sub' => 'user-uuid',
    'email' => '[email protected]',
    'iat' => time(),
    'exp' => time() + 3600,
], $privateKeyPem, 'RS256', 'test-key');

$this->withHeader('Cf-Access-Jwt-Assertion', $jwt)
    ->getJson('/internal-api/reports')
    ->assertOk();
xml
<env name="CLOUDFLARE_ZERO_TRUST_ENABLED" value="false"/>