corbado/php-sdk
Official Corbado PHP SDK for adding passwordless authentication to PHP apps. Supports passkeys, email magic links, and session management with simple backend integration for secure, frictionless sign-in.
Before you start, note the status: this repository is archived (last release 2025-03-24, zero dependents). It still installs and works, but there is no upstream maintenance, no security patches, and the API contract can drift from Corbado's live backend. Treat it as a vendor reference implementation you may need to fork, not as a dependency you can safely forget about.
Minimal path:
composer require corbado/php-sdk
pro-...) and an API Secret. The secret is server-side only — never ship it to the frontend.README.md, then src/Config.php, then src/Services/Sessions.php. The README covers the frontend component setup; Config is where every knob lives (project ID, secret, API base URL, short-session cookie name, PSR-18 client, PSR-3 logger); Sessions is the one service you will call on nearly every authenticated request.// config/corbado.php
return [
'project_id' => env('CORBADO_PROJECT_ID'),
'api_secret' => env('CORBADO_API_SECRET'),
'cookie_name' => env('CORBADO_SESSION_COOKIE', 'cbo_short_session'),
];
$this->app->singleton(\Corbado\SDK::class, function ($app) {
$config = new \Corbado\Config();
$config->setProjectId(config('corbado.project_id'));
$config->setApiSecret(config('corbado.api_secret'));
$config->setShortSessionCookieName(config('corbado.cookie_name'));
// optionally: ->setHttpClient(...), ->setLogger(...)
return new \Corbado\SDK($config);
});
ResolveCorbadoUser middleware that calls $sdk->sessions()->getCurrentUser() and stashes the user on the request. Corbado's frontend widget performs the passkey ceremony and sets the cbo_short_session cookie; your Laravel backend only verifies it. That asymmetry is the single most important mental model to internalize.You are productive within an hour if you already have a Corbado project; the SDK is a thin, typed wrapper over the REST API, not a framework.
Session verification as middleware. The canonical day-to-day pattern:
$user = $this->sdk->sessions()->getCurrentUser();
if ($user === null) {
return redirect()->route('login'); // anonymous, not an error
}
$request->attributes->set('corbado_user', $user);
Distinguish three states explicitly: null (no/invalid session), a User (authenticated), and a thrown exception (misconfiguration, network, upstream 5xx). Conflating them into one 401 makes production debugging miserable.
Guard / user-provider bridge. Wrap the Corbado user in a small Eloquent model keyed by getUserID() (user_...), created lazily on first login. This gives you Auth::user(), policies, and $request->user() for free while Corbado remains the identity authority. Keep the local row a projection — never treat it as the source of truth for credentials.
Login / logout flow. Login is browser-side (Corbado component). On logout, call Corbado's logout endpoint on the frontend to clear the cookie, then Auth::logout() and invalidate the Laravel session server-side. Do not try to clear Corbado's cookie from PHP unless it is genuinely your domain and path.
Profile and passkey management. Use $sdk->users()->get($userID) for profile data and the identifiers service to list/append/remove passkeys in an account-settings page. This is where the SDK earns its keep beyond auth: passkey enrolment UX, backup-key management, and identifier listing without hand-rolling REST calls.
Email/phone OTP and magic links appear as separate services (emailOTPs(), phoneOTPs(), emailLinks()). Useful for fallback recovery flows when a user loses their passkey device — but each call is a real API round-trip and often a real email/SMS cost, so route them through queued jobs, not inline in a request.
Testing. Because the SDK accepts a PSR-18 client, you can inject a fake HTTP client in tests and assert on the request payloads, or bind a stub SDK subclass in the container. Both are cleaner than hitting the sandbox project in CI. Keep a small fixture set of real response bodies — the SDK's entities are simple value objects, so assertions stay readable.
composer.json and add a note in your README that you own this fork. If Corbado changes response shapes, nothing will warn you but a runtime exception.getCurrentUser() returning null is not a failure. It means the cookie was absent, expired, or invalid. Throwing on null will produce spurious 500s from expired browser tabs.null, check that setShortSessionCookieName() matches what the frontend widget writes. A mismatch fails silently.Secure, so http://localhost behaves differently than production. Test the real flow over a tunnel, not on plain localhost.AssertException (bad config / bad arguments — fail fast, this is a deploy bug), ServerException (upstream/network — retry or degrade), validation exceptions (bad user input — surface to the form). Catch the base CorbadoException in a global handler and map to 503 vs 401 accordingly; do not let vendor exceptions escape to the framework handler.getCurrentUser() can hit Corbado's API. On a page with 20 AJAX calls you will make 20 verifications. Cache sessionToken => user in Redis for the token's remaining lifetime (short — treat it as a few minutes, not hours) and flush on logout.Config and include Corbado's correlation ID in your exception context. It is the only thing vendor support (historically) asked for.src/ are unstable. Stick to the four or five public service calls documented in the README and wrap them in your own CorbadoService facade so a future migration (or fork) touches one file.Bottom line for day-to-day work: the SDK is a competent, narrow adapter that makes "verify a Corbado session inside Laravel" a ten-line job. The engineering cost is not the integration, it is the abandonment risk — budget for the possibility that you will maintain this class yourself within a year.
How can I help you explore Laravel packages today?