Why zero‑trust is no longer optional for Laravel developers
Imagine a breach that compromises a single API key and instantly exposes every internal admin panel. In 2023, Gartner reported that 70% of data breaches exploited weak authentication, a statistic that forces modern Laravel teams to adopt zero‑trust principles. Zero‑trust means no user or service is trusted by default, even if they sit inside the corporate network. Implementing it in a Laravel project requires a combination of identity federation, strict access policies, and robust session handling—all of which can be achieved with Cloudflare Access, OIDC, and Laravel Fortify.
System requirements and preparation
Before diving into code, ensure your environment meets these baseline requirements: PHP 8.1 or newer, Laravel 10.x, Composer 2.5+, and an active Cloudflare account with Access enabled. You also need a domain that routes through Cloudflare so that Access can enforce policies. Finally, create a Cloudflare Access Application that will act as an OpenID Connect (OIDC) provider; the client ID and secret generated here will be used by Laravel.
Configuring Cloudflare Access as an OIDC provider
Log in to the Cloudflare dashboard, navigate to "Access → Applications", and click "Add an application". Choose "Self‑hosted" and fill in the following fields: Name (e.g., "Laravel Admin"), Domain (your Laravel app’s URL), and Session Duration (recommended 8 hours). Under "Authentication", select "OIDC" and copy the Issuer URL, Client ID, and Client Secret. These three values will be referenced in Laravel’s service configuration.
Adding OIDC credentials to Laravel
Open config/services.php and insert a new entry for Cloudflare. The snippet below shows the exact structure; notice the escaped HTML entities for the PHP tags.
<?php return [ // Other services ... 'cloudflare' => [ 'client_id' => env('CLOUDFLARE_CLIENT_ID'), 'client_secret' => env('CLOUDFLARE_CLIENT_SECRET'), 'redirect' => env('CLOUDFLARE_REDIRECT_URI'), 'issuer' => env('CLOUDFLARE_ISSUER'), ],];Then add the corresponding environment variables to .env:
CLOUDFLARE_CLIENT_ID=your_client_id CLOUDFLARE_CLIENT_SECRET=your_client_secret CLOUDFLARE_REDIRECT_URI=https://yourdomain.com/auth/callback CLOUDFLARE_ISSUER=https://YOUR_TEAM.cloudflareaccess.comLaravel will now treat Cloudflare as an OIDC provider via the generic Socialite driver.
Integrating OIDC with Laravel Fortify
Fortify supplies the authentication scaffolding, but you must tell it to use the OIDC guard for the admin guard. Create a custom provider in app/Providers/FortifyServiceProvider.php and register the callback route.
use Illuminate\Support\Facades\Route; use Laravel\Fortify\Fortify; class FortifyServiceProvider extends ServiceProvider { public function boot() { Fortify::authenticateUsing(function (Request $request) { $user = Socialite::driver('cloudflare')->stateless()->user(); return \App\Models\User::firstOrCreate([ 'email' => $user->getEmail(), ], [ 'name' => $user->getName(), 'cloudflare_id' => $user->getId(), ]); }); Route::get('/auth/callback', function () { // Handled by Fortify's default callback logic // No additional code needed here })->name('login.callback'); } }Make sure the User model contains a cloudflare_id column; run a migration to add it:
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; class AddCloudflareIdToUsers extends Migration { public function up() { Schema::table('users', function (Blueprint $table) { $table->string('cloudflare_id')->nullable(); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('cloudflare_id'); }); }}Now every successful Cloudflare login creates or updates a local user record, tying the external identity to your Laravel authorization layer.
Enforcing zero‑trust policies with Cloudflare Access
Zero‑trust is enforced at the edge: in the Cloudflare dashboard, add policies that require multi‑factor authentication, IP reputation checks, or device posture verification before granting a token. For example, a policy that reads "Require MFA for any request to /admin/*" will block unauthenticated traffic before it even reaches Laravel. Because the token is short‑lived (default 30 minutes), compromised credentials lose value quickly.
Session hardening and logout handling
Laravel Fortify stores the OIDC token in the session. To avoid token leakage, configure the session driver to redis and set SESSION_LIFETIME=30 in .env. Additionally, implement a logout route that revokes the Cloudflare token via the OIDC revocation endpoint:
use GuzzleHttp\Client; Route::post('/logout', function (Request $request) { $token = $request->session()->get('access_token'); $client = new Client(); $client->post(config('services.cloudflare.issuer').'/oauth/revoke', [ 'form_params' => [ 'token' => $token, 'client_id' => config('services.cloudflare.client_id'), 'client_secret' => config('services.cloudflare.client_secret'), ], ]); Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/');});This ensures that once a user clicks "Logout" the remote session is also terminated, aligning with zero‑trust expectations.
Testing, monitoring, and continuous improvement
After deployment, use Cloudflare’s Access logs to audit every authentication event. Pair this with Laravel Telescope to watch for unexpected session creations. A practical tip: schedule a nightly job that checks token expiration against Cloudflare’s introspection endpoint and forces re‑authentication if a token is older than the policy threshold. Over time, you’ll see a measurable drop in unauthorized attempts—often a 40% reduction after the first month of zero‑trust enforcement.
Conclusion
By combining Cloudflare Access, OIDC, and Laravel Fortify, you can transform a traditional Laravel application into a zero‑trust‑ready service without rewriting the entire authentication stack. The key steps are: configure Cloudflare as an OIDC provider, wire the provider into Fortify’s authentication flow, enforce edge‑level policies, and harden session handling. The result is a seamless user experience backed by modern security guarantees, letting you focus on business logic rather than patchwork access controls.
Sources
- Cloudflare Access Documentation
- Laravel Fortify Official Documentation
- OpenID Connect Core Specification
Author: Mahmut Sarıkaya — sarikayadev.com