PHPackages                             cboxdk/laravel-id-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. cboxdk/laravel-id-client

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

cboxdk/laravel-id-client
========================

Laravel/PHP consumer SDK for Cbox ID — turnkey OIDC login, hosted profile-management redirect, machine tokens, and webhook verification against a Cbox ID instance.

v0.11.0(1w ago)1366↑62.5%MITPHPPHP ^8.4CI passing

Since Jul 16Pushed 1w agoCompare

[ Source](https://github.com/cboxdk/laravel-id-client)[ Packagist](https://packagist.org/packages/cboxdk/laravel-id-client)[ RSS](/packages/cboxdk-laravel-id-client/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (8)Dependencies (32)Versions (16)Used By (0)

cboxdk/laravel-id-client
========================

[](#cboxdklaravel-id-client)

Laravel/PHP **consumer** SDK for Cbox ID — the package a *product* installs to authenticate its users against a running Cbox ID instance (the opposite end from [`cboxdk/laravel-id`](../laravel-id), which *is* the identity platform).

It speaks standard OpenID Connect, so integrating is a login redirect and a callback — not a rewrite — with PKCE, CSRF `state`, a nonce, and full id\_token signature/issuer/ audience verification handled for you. It adds the two conveniences a hosted-identity product needs: a **redirect to the instance's hosted profile-management page**, and back-channel helpers (**machine tokens, userinfo, introspection, revocation, webhook verification**).

Part of **Cbox ID** — the self-hostable, Laravel-native identity platform. MIT licensed.

Migrating off an old login
--------------------------

[](#migrating-off-an-old-login)

While you move users to Cbox ID, it can ask your system whether an email and password it has never seen are good — and import that person on the yes. You write the one function that knows your database; the handler owns the signature, the freshness window and the constant-time compare:

```
use Cbox\Id\Client\Migration\{LegacyLogin, LegacyUser};

Route::post('/cbox-legacy', LegacyLogin::using(function (string $email, string $password): ?LegacyUser {
    $row = DB::connection('legacy')->table('users')->where('email', $email)->first();

    return $row && Hash::check($password, $row->password)
        ? new LegacyUser($row->email, $row->name, $row->confirmed_at !== null, $row->password)
        : null;
}));
```

Set `CBOX_ID_LEGACY_SECRET` to at least 32 characters. `LegacyLogin::using()` refuses to build without it — at boot, where somebody is looking, rather than as a 500 that reads as an outage.

Return `null` for "wrong password". **Throwing is different**: it means your store could not decide, and is answered with 503 so Cbox ID refuses the sign-in rather than reading an outage as a bad credential. Returning the stored hash lets the person keep their password verbatim; omit it and Cbox ID hashes the one they just proved they know.

No route is registered for you, deliberately: unlike webhooks, this endpoint receives passwords, so where it lives and what sits in front of it should be a decision somebody made rather than a default they inherited.

Install
-------

[](#install)

```
composer require cboxdk/laravel-id-client
php artisan vendor:publish --tag=cbox-id-client-config
```

Requires PHP `^8.4` and Laravel 12 or 13.

Configure the instance and your OAuth client (registered on the Cbox ID instance):

```
CBOX_ID_ISSUER=https://acme.cboxid.com
CBOX_ID_CLIENT_ID=client_...
CBOX_ID_CLIENT_SECRET=secret_...
CBOX_ID_REDIRECT=https://app.acme.com/auth/callback
```

Every endpoint (authorize, token, userinfo, jwks) is discovered from the issuer, so that's usually all you configure.

Log a user in
-------------

[](#log-a-user-in)

```
use Cbox\Id\Client\Facades\CboxId;

// routes/web.php
Route::get('/auth/redirect', fn () => CboxId::redirect());          // → Cbox ID login

Route::get('/auth/callback', function (\Illuminate\Http\Request $request) {
    $cbox = CboxId::authenticate($request);   // verifies state, PKCE, id_token

    $user = User::updateOrCreate(
        ['cbox_id' => $cbox->id],                              // the stable `sub`
        ['email' => $cbox->email, 'name' => $cbox->name],
    );

    auth()->login($user);
    return redirect('/dashboard');
});
```

`authenticate()` returns a `CboxUser` — `id` (subject), `email`, `name`, `organizationId`, the full verified `claims`, and the `accessToken` / `refreshToken`. It throws `InvalidState` on a forged/stale callback and `AuthenticationFailed`otherwise.

Draw your own sign-in box
-------------------------

[](#draw-your-own-sign-in-box)

Reading the environment's public configuration from PHP lets a Blade page render a sign-in box in the customer's own branding — with no JavaScript SDK, and no flash of unstyled form while one loads. A **publishable** key is the opposite of the client secret above: public on purpose, and useful only from the origins its owner listed against it.

```
// config/cbox-id-client.php — CBOX_ID_PUBLISHABLE_KEY
use Cbox\Id\Client\Frontend\FrontendClient;

$config = app(FrontendClient::class)->config();

$config->endpoint('authorization');  // where the form posts on to
$config->social;                     // the buttons this environment has enabled
$config->accent();                   // the customer's brand colour
$config->isLive();                   // false for a pk_test_ key — draw the badge
```

And who is signed in, given a token you already hold:

```
$session = app(FrontendClient::class)->session($accessToken);

$session->signedIn();          // false is a state, not an error
$session->user?->initials();   // 'AL' — for the avatar fallback
```

The key grants nothing on its own: `session()` is authorized by the token, and `config()`answers the same document to everybody. The configuration is cached for a minute (`CBOX_ID_FRONTEND_CACHE_TTL`) because it decides layout and a page render is not a good place for a network call.

**Before it works:** an operator turns the Frontend API on (`CBOX_ID_FRONTEND_API=true` — it is off by default) and mints a key under **Developers → Frontend keys**, listing the origins allowed to use it. Exact matches only: `https://acme.com` does not cover `https://www.acme.com`.

Send users to hosted profile management
---------------------------------------

[](#send-users-to-hosted-profile-management)

Let users manage their own password, MFA, passkeys and sessions on the instance's hosted account page, then come back to your app:

```
Route::get('/account', fn () => CboxId::redirectToProfile(returnTo: route('dashboard')));
// or just the URL: CboxId::profileUrl(route('dashboard'))
```

Call Cbox ID APIs
-----------------

[](#call-cbox-id-apis)

```
$token   = CboxId::machineToken(['api.read']);       // client-credentials (M2M)
$claims  = CboxId::userinfo($accessToken);           // OIDC userinfo
$active  = CboxId::introspect($token)['active'];      // RFC 7662
CboxId::revoke($refreshToken, 'refresh_token');      // RFC 7009
```

Revoking a refresh token drops the whole token family — that's what "sign out everywhere" needs.

Verify a webhook / action
-------------------------

[](#verify-a-webhook--action)

```
$ok = CboxId::verifyWebhook(
    payload: $request->getContent(),                 // the RAW body
    signatureHeader: $request->header('X-Cbox-Signature'),
    secret: config('services.cbox.webhook_secret'),
);
abort_unless($ok, 400);
```

Receive provisioning webhooks (outbound provisioning)
-----------------------------------------------------

[](#receive-provisioning-webhooks-outbound-provisioning)

Instead of standing up a SCIM server, register a hook and let the SDK verify and route Cbox ID's signed events. Set `CBOX_ID_WEBHOOK_SECRET`, then in a service provider's `boot()`:

```
use Cbox\Id\Client\Facades\CboxIdWebhooks;

CboxIdWebhooks::on('organization.member_added', fn ($e) => Seat::allocate($e->string('user_id')));
CboxIdWebhooks::on('organization.member_removed', fn ($e) => Seat::release($e->string('user_id')));
CboxIdWebhooks::on('role.assigned', fn ($e) => /* … */);
CboxIdWebhooks::on('*', fn ($e) => Log::info('cbox event', ['type' => $e->type]));
```

The SDK mounts a signed receiver at `POST /cbox-id/webhooks` (configurable). Register that URL as a webhook endpoint on your Cbox ID instance (Developers → Webhooks), subscribe it to the event types you handle, and copy its signing secret into `CBOX_ID_WEBHOOK_SECRET`. Signature verification (HMAC-SHA256, replay-bounded) and JSON parsing are handled for you; a bad or stale signature is rejected before anything runs.

**The receiver is slim.** It verifies, acknowledges immediately, and runs your handlers on a queued job (`ProcessCboxIdWebhook`) — so a slow handler never stalls the response or trips the dispatcher's timeout/retry. Point `CBOX_ID_WEBHOOK_QUEUE_CONNECTION` / `CBOX_ID_WEBHOOK_QUEUE` at a real async queue in production (with `QUEUE_CONNECTION=sync`the job runs inline). Each event's `deliveryId` is stable, so dedupe retries with it.

License
-------

[](#license)

MIT © Cbox.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance98

Actively maintained with recent releases

Popularity19

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

15

Last Release

13d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b9761a79e61f2d5b9d650510dfb3555da18daf38f027aa84012c937e397e39a7?d=identicon)[cboxdk](/maintainers/cboxdk)

---

Top Contributors

[![sylvesterdamgaard](https://avatars.githubusercontent.com/u/2431914?v=4)](https://github.com/sylvesterdamgaard "sylvesterdamgaard (23 commits)")

---

Tags

clientlaravelsdkAuthenticationSSOidentityoidccbox

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/cboxdk-laravel-id-client/health.svg)

```
[![Health](https://phpackages.com/badges/cboxdk-laravel-id-client/health.svg)](https://phpackages.com/packages/cboxdk-laravel-id-client)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k118.2M1.0k](/packages/laravel-socialite)[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

80732.6M272](/packages/laravel-mcp)[illuminate/auth

The Illuminate Auth package.

10528.8M1.4k](/packages/illuminate-auth)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k59.5M717](/packages/laravel-scout)[illuminate/routing

The Illuminate Routing package.

1419.6M3.8k](/packages/illuminate-routing)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
