{"id":34010646,"url":"https://github.com/cerberus-iam/laravel-sdk","last_synced_at":"2026-04-24T07:34:34.159Z","repository":{"id":322735183,"uuid":"1090670996","full_name":"cerberus-iam/laravel-sdk","owner":"cerberus-iam","description":"🛡️ Cerberus IAM Laravel Integration Package (PHP)","archived":false,"fork":false,"pushed_at":"2025-11-08T08:20:47.000Z","size":369,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-14T12:27:08.745Z","etag":null,"topics":["authorization-code-flow","iam","jwks","jwt","laravel","laravel-auth","laravel-package","middleware","oauth2","oidc","openid-connect","pkce","rbac","roles","single-sign-on","sso","user-provisioning"],"latest_commit_sha":null,"homepage":"https://cerberus-iam.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cerberus-iam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-06T01:29:52.000Z","updated_at":"2025-11-12T17:46:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cerberus-iam/laravel-sdk","commit_stats":null,"previous_names":["cerberus-iam/laravel-iam","cerberus-iam/laravel-sdk"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cerberus-iam/laravel-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerberus-iam%2Flaravel-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerberus-iam%2Flaravel-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerberus-iam%2Flaravel-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerberus-iam%2Flaravel-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cerberus-iam","download_url":"https://codeload.github.com/cerberus-iam/laravel-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cerberus-iam%2Flaravel-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32214418,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T03:15:14.334Z","status":"ssl_error","status_checked_at":"2026-04-24T03:15:11.608Z","response_time":64,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorization-code-flow","iam","jwks","jwt","laravel","laravel-auth","laravel-package","middleware","oauth2","oidc","openid-connect","pkce","rbac","roles","single-sign-on","sso","user-provisioning"],"created_at":"2025-12-13T12:11:43.383Z","updated_at":"2026-04-24T07:34:34.143Z","avatar_url":"https://github.com/cerberus-iam.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cerberus IAM | Laravel SDK\n\nA framework-agnostic bridge that lets any Laravel application outsource authentication and user directory responsibilities to the [Cerberus IAM API](../README.md).  Instead of maintaining local passwords, session stores, and role logic, you attach this package, configure a guard, and delegate the heavy lifting to Cerberus.\n\n---\n\n## Requirements\n\n| Component          | Version                           |\n| ------------------ | --------------------------------- |\n| PHP                | 8.2+                              |\n| Laravel components | 10.x / 11.x                       |\n| cerberus-iam/api   | Compatible REST instance          |\n| jerome/filterable  | ^2.0 (optional request filtering) |\n\n\u003e The package is designed for multi-tenant environments. Ensure the API instance you point to has the desired organisations, roles, and OAuth clients configured.\n\n---\n\n## Installation\n\n```bash\ncomposer require cerberus-iam/laravel-sdk\nphp artisan vendor:publish --provider=\"CerberusIAM\\\\Providers\\\\CerberusIamServiceProvider\" --tag=config\n```\n\nPublishing yields `config/cerberus-iam.php` – the single source of truth for connecting to the IAM platform.\n\n### Environment Variables\n\n```dotenv\nCERBERUS_IAM_URL=https://api.cerberus-iam.com\nCERBERUS_IAM_CLIENT_ID=\nCERBERUS_IAM_CLIENT_SECRET=\nCERBERUS_IAM_USERNAME=\"admin@cerberus-iam.com\"\nCERBERUS_IAM_PASSWORD=\"Password123!\"\nCERBERUS_IAM_REDIRECT_URI=\"${APP_URL}/cerberus/callback\"\nCERBERUS_IAM_SCOPES=\"openid profile email\"\nCERBERUS_IAM_SESSION_COOKIE=cerb_sid\nCERBERUS_IAM_ORG_SLUG=cerberus-iam\nCERBERUS_IAM_HTTP_TIMEOUT=10\nCERBERUS_IAM_HTTP_RETRY=true\nCERBERUS_IAM_HTTP_RETRY_ATTEMPTS=2\nCERBERUS_IAM_HTTP_RETRY_DELAY=100\nCERBERUS_IAM_PORTAL_URL=https://app.cerberus-iam.com\nCERBERUS_IAM_PROFILE_URL=\nCERBERUS_IAM_SECURITY_URL=\nCERBERUS_IAM_REDIRECT_AFTER_LOGIN=/dashboard\nCERBERUS_IAM_USER_MODEL=\n```\n\n### HTTP Client Customisation\n\nAll outbound calls now run through Laravel's HTTP client, so you get first-class support for `Http::fake()`, middleware, and macros. Tune timeouts or retry behaviour via `cerberus-iam.http` in the config (or the matching environment variables shown above). If you need deeper customisation you can register macros/global middleware on the `Http` facade the same way you would in any Laravel app—those hooks automatically apply to the SDK because it resolves the shared HTTP factory from the container.\n\n---\n\n## Database Requirements\n\nCerberus IAM uses UUIDs for user identifiers. You must configure your Laravel application's database to support this.\n\n### Sessions Table\n\nUpdate your sessions table migration to use string for `user_id`:\n\n```php\n$table-\u003estring('user_id')-\u003enullable()-\u003eindex();\n```\n\nIf you already have a sessions table with a bigint `user_id` column, create a migration to convert it:\n\n```php\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    public function up(): void\n    {\n        Schema::table('sessions', function (Blueprint $table) {\n            $table-\u003estring('user_id')-\u003enullable()-\u003echange();\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::table('sessions', function (Blueprint $table) {\n            $table-\u003eunsignedBigInteger('user_id')-\u003enullable()-\u003echange();\n        });\n    }\n};\n```\n\n### User Model (Optional but Recommended)\n\nBy default, the SDK retrieves user data from Cerberus IAM on every request (stateless mode). For better performance and integration with Laravel's ecosystem, you can configure the SDK to sync users to a local database table.\n\nTo enable database-backed authentication, set the `CERBERUS_IAM_USER_MODEL` environment variable:\n\n```dotenv\nCERBERUS_IAM_USER_MODEL=App\\\\Models\\\\User\n```\n\nYour `users` table migration should include:\n\n```php\nSchema::create('users', function (Blueprint $table) {\n    $table-\u003eid();\n    $table-\u003estring('cerberus_id')-\u003eunique(); // UUID from Cerberus IAM\n    $table-\u003estring('name');\n    $table-\u003estring('email')-\u003eunique();\n\n    // Optional fields\n    $table-\u003estring('first_name')-\u003enullable();\n    $table-\u003estring('last_name')-\u003enullable();\n    $table-\u003estring('organisation_id')-\u003enullable();\n    $table-\u003estring('organisation_slug')-\u003enullable();\n\n    $table-\u003etimestamps();\n});\n```\n\nYour User model must:\n\n1. Implement `Illuminate\\Contracts\\Auth\\Authenticatable` (typically via `Illuminate\\Foundation\\Auth\\User`)\n2. Have `cerberus_id`, `name`, and `email` in the `$fillable` array\n3. Optionally include `first_name`, `last_name`, `organisation_id`, `organisation_slug`\n\nExample User model:\n\n```php\nnamespace App\\Models;\n\nuse Illuminate\\Foundation\\Auth\\User as Authenticatable;\n\nclass User extends Authenticatable\n{\n    protected $fillable = [\n        'cerberus_id',\n        'name',\n        'email',\n        'first_name',\n        'last_name',\n        'organisation_id',\n        'organisation_slug',\n    ];\n}\n```\n\nWhen database-backed authentication is enabled:\n\n- Users are automatically created/updated in your local database on login\n- Subsequent requests retrieve the user from your database (fast)\n- User data is refreshed from Cerberus on each login\n\n---\n\n## Guard Setup\n\nReplace the default `web` guard (or add a dedicated guard) in `config/auth.php`:\n\n```php\n'guards' =\u003e [\n    'web' =\u003e [\n        'driver' =\u003e 'cerberus',\n        'provider' =\u003e 'cerberus-users',\n        'scopes' =\u003e ['openid', 'profile', 'email'],\n    ],\n],\n\n'providers' =\u003e [\n    'cerberus-users' =\u003e [\n        'driver' =\u003e 'cerberus',\n    ],\n],\n```\n\nThe package registers:\n\n- `cerberus` guard (stateful)\n- `cerberus` user provider (fetches profiles from IAM as-needed)\n- Middleware alias `cerberus.auth`\n\n---\n\n## Authentication Flow\n\n1. **Incoming request** hits a protected route.\n2. `EnsureCerberusAuthenticated` checks the guard; guests are redirected to Cerberus using PKCE.\n3. After login/consent, the IAM redirects to `/cerberus/callback` (included route) with an auth code.\n4. `CerberusGuard::loginFromAuthorizationCode()` exchanges the code for tokens, stores them via the `TokenStore`, and pulls the user profile from `/oauth2/userinfo`.\n5. Subsequent requests reuse access tokens, automatically refresh them with the IAM when expired, and fall back to Cerberus' session cookie if present.\n\n### Protecting Routes\n\n```php\nRoute::middleware('cerberus.auth')-\u003egroup(function () {\n    Route::view('/dashboard', 'dashboard');\n});\n```\n\nYou can override the default redirect target by passing it as middleware parameter:\n\n```php\nRoute::middleware('cerberus.auth:/account')-\u003eget('/settings', SettingsController::class);\n```\n\n---\n\n## Callback Route\n\nThe package registers `/cerberus/callback` under the `web` middleware group.  If you already have a route with that URI, disable the auto-registration by caching routes and defining your own controller that proxies to `CerberusGuard::loginFromAuthorizationCode()`.\n\n```php\nuse CerberusIAM\\Auth\\CerberusGuard;\nuse Illuminate\\Support\\Facades\\Auth;\n\nRoute::get('/cerberus/callback', function (Request $request) {\n    /** @var CerberusGuard $guard */\n    $guard = Auth::guard('cerberus');\n    $guard-\u003eloginFromAuthorizationCode(\n        $request-\u003equery('code'),\n        $request-\u003equery('state')\n    );\n\n    return redirect()-\u003eintended(config('cerberus-iam.redirect_after_login'));\n});\n```\n\n---\n\n## Token \u0026 State Storage\n\nBy default tokens live in the session using `CerberusIAM\\Support\\Stores\\SessionTokenStore`.  You can swap it for Redis or any persistent store by binding the interfaces:\n\n```php\nuse CerberusIAM\\Contracts\\TokenStore;\nuse CerberusIAM\\Contracts\\OAuthStateStore;\nuse App\\Auth\\RedisTokenStore;\nuse App\\Auth\\RedisOAuthStateStore;\n\n$this-\u003eapp-\u003ebind(TokenStore::class, fn () =\u003e new RedisTokenStore());\n$this-\u003eapp-\u003ebind(OAuthStateStore::class, fn () =\u003e new RedisOAuthStateStore());\n```\n\nBoth interfaces are minimal:\n\n```php\ninterface TokenStore {\n    public function store(array $payload): void;\n    public function retrieve(): ?array;\n    public function clear(): void;\n}\n```\n\nThe guard asks the store for `access_token`, `refresh_token`, and optionally `expires_at` (ISO8601).  Refresh happens automatically when `expires_at` is in the past.\n\n---\n\n## HTTP Client \u0026 Facade\n\n`CerberusIAM\\Http\\Clients\\CerberusClient` delegates to Laravel's HTTP client, so anything you register via `Http::macro()` or `Http::middleware()` flows through automatically. Use the facade when you need low-level access:\n\n```php\nuse CerberusIAM\\Facades\\CerberusIam;\n\n$jwks = CerberusIam::url('/oauth2/jwks.json');\n$response = CerberusIam::getUserInfo($accessToken);\n```\n\nThe client respects the timeout/retry options defined in `cerberus-iam.php`.\n\n---\n\n## User Directory Proxy\n\nCerberus exposes administrative endpoints (e.g. `/v1/admin/users`).  To keep your Laravel controllers tidy, use the bundled repository + filter pipeline:\n\n```php\nuse CerberusIAM\\Repositories\\UserDirectoryRepository;\nuse Illuminate\\Http\\Request;\n\nclass AdminUserController\n{\n    public function __invoke(Request $request, UserDirectoryRepository $repository)\n    {\n        $directory = $repository-\u003elist(\n            organisationSlug: $request-\u003eheader('X-Org-Domain'),\n            request: $request,\n            options: ['per_page' =\u003e 25],\n            accessToken: auth()-\u003eguard('cerberus')-\u003egetTokenStore()-\u003eretrieve()['access_token'] ?? null,\n            sessionToken: $request-\u003ecookie(config('cerberus-iam.session_cookie'))\n        );\n\n        return view('admin.users.index', ['users' =\u003e $directory['data'] ?? []]);\n    }\n}\n```\n\n`UserDirectoryFilter` leverages [`jerome/filterable`](https://github.com/Thavarshan/filterable) so your existing HTTP filters map to IAM query parameters (`filter[email]`, `filter[mfa_enabled]`, etc.).\n\n---\n\n## Customising Behaviour\n\n| Concern        | Contract                                | Default                                | Notes                                 |\n| -------------- | --------------------------------------- | -------------------------------------- | ------------------------------------- |\n| IAM client     | `CerberusIAM\\Contracts\\IamClient`       | `Http\\Clients\\CerberusClient`          | Replace to mock or extend API calls   |\n| Token store    | `CerberusIAM\\Contracts\\TokenStore`      | Session                                | Ideal place for Redis-backed storage  |\n| OAuth state    | `CerberusIAM\\Contracts\\OAuthStateStore` | Session                                | Persist `state` + PKCE verifier       |\n| User directory | `CerberusIAM\\Contracts\\UserRepository`  | `Repositories\\UserDirectoryRepository` | Swap if you prefer GraphQL or caching |\n\nBind your implementation in any service provider to override defaults.\n\n---\n\n## Testing \u0026 Local Development\n\nThe package ships with a Pest suite backed by Orchestra Testbench.\n\n```bash\ncomposer test\n```\n\nTo test against a live Cerberus instance locally:\n\n1. Run the IAM API (`npm run dev` inside the main repo) and ensure an OAuth client exists.\n2. Point `CERBERUS_IAM_URL` to that instance.\n3. Configure the guard in a sample Laravel app, apply the middleware, and log in.\n\n### Live Integration Tests Against \u003chttps://api.cerberus-iam.com\u003e\n\nPest now includes an optional `integration` group that exercises the SDK against the deployed API (`https://api.cerberus-iam.com`). Because these tests create real sessions and call privileged admin endpoints, they are skipped unless the following environment variables are defined:\n\n| Variable                      | Required        | Description                                                                  |\n| ----------------------------- | --------------- | ---------------------------------------------------------------------------- |\n| `CERBERUS_IAM_BASE_URL`       | Yes             | Base URL for the live API (`https://api.cerberus-iam.com`)                   |\n| `CERBERUS_IAM_USERNAME`       | Yes             | Email for a Cerberus account that can log in via `/v1/auth/login`            |\n| `CERBERUS_IAM_PASSWORD`       | Yes             | Password for the live test account                                           |\n| `CERBERUS_IAM_CLIENT_ID`      | For admin flows | OAuth client ID with permission to call admin endpoints                      |\n| `CERBERUS_IAM_CLIENT_SECRET`  | For admin flows | Client secret for the above OAuth client (required for client credentials)   |\n| `CERBERUS_IAM_ORG_SLUG`       | Optional        | Organisation slug to scope admin requests (falls back to the login response) |\n| `CERBERUS_IAM_SESSION_COOKIE` | Optional        | Session cookie name (defaults to `cerb_sid`)                                 |\n| `CERBERUS_IAM_SCOPES`         | Optional        | Space-delimited scopes for the OAuth client (default `openid profile email`) |\n| `CERBERUS_IAM_ADMIN_SCOPES`   | Optional        | Additional scopes for client-credential admin calls (default `users:read`)   |\n| `CERBERUS_IAM_REDIRECT_URI`   | Optional        | Redirect URI associated with the OAuth client                                |\n| `CERBERUS_IAM_TIMEOUT`        | Optional        | HTTP timeout (seconds) for the live calls, default `15`                      |\n\nOnce configured, run only the live tests with:\n\n```bash\ncomposer test -- --group=integration\n```\n\nThe tests log out sessions automatically, but they still mutate real data—use service accounts and non-production organisations wherever possible.\n\n---\n\n## Troubleshooting\n\n| Symptom                                                             | Likely Cause                       | Fix                                                                          |\n| ------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------- |\n| Redirect loop back to Cerberus                                      | callback URL mismatch              | Confirm `CERBERUS_IAM_REDIRECT_URI` matches the client settings              |\n| `invalid_state` exception                                           | Session not persisting             | Check session driver, domain, and ensure HTTPS in production                 |\n| `Route [/cerberus/callback] not defined`                            | Routes cached without package boot | Clear route cache or define the route manually                               |\n| 401 when listing users                                              | Missing organisation slug header   | Pass `X-Org-Domain` or adjust repository call                                |\n| `Invalid text representation: invalid input syntax for type bigint` | Sessions table `user_id` is bigint | Change sessions table `user_id` column to string (see Database Requirements) |\n\n---\n\n## Contributing\n\n1. `composer install`\n2. Make changes (follow PSR-12, small focused commits)\n3. `composer test`\n4. Submit PR referencing the IAM change if relevant\n\nBug reports and feature requests are welcome via issues in the main Cerberus IAM repository.\n\n---\n\n## License\n\nThis project is licensed under the MIT License – see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerberus-iam%2Flaravel-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcerberus-iam%2Flaravel-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcerberus-iam%2Flaravel-sdk/lists"}