use-lock / server
OpenID Connect provider and authentication UI for Laravel
Requires
- php: ^8.5
- ext-sodium: *
- bacon/bacon-qr-code: ^3.1
- illuminate/auth: ^13.0
- illuminate/bus: ^13.0
- illuminate/console: ^13.0
- illuminate/contracts: ^13.0
- illuminate/cookie: ^13.0
- illuminate/database: ^13.0
- illuminate/http: ^13.0
- illuminate/queue: ^13.0
- illuminate/session: ^13.0
- illuminate/support: ^13.0
- illuminate/validation: ^13.0
- illuminate/view: ^13.0
- laravel/passkeys: ^0.2.1
- lattice-php/lattice: >=0.77 <1.0
- lcobucci/clock: ^3.2
- lcobucci/jwt: ^5.0
- phpseclib/phpseclib: ^3.0.15
- pragmarx/google2fa: ^9.0
Requires (Dev)
- bambamboole/extended-testbench: ^0.6.1
- larastan/larastan: ^3.0
- laravel/boost: ^2.6
- laravel/pint: ^1.16
- mockery/mockery: ^1.6
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-phpstan: ^5.0
- rector/rector: ^2.4
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
An OpenID Connect provider and Lattice authentication UI for Laravel, shipped as one Composer package.
What you get
OIDC provider
- Signed RS256
id_tokens, a/.well-known/openid-configurationdiscovery document, and a JWKS endpoint (RFC 7638kids). userinfo, RP-initiated logout, OIDC back-channel logout, RFC 7662 introspection, and RFC 7009 revocation.- RFC 9068 structured
at+jwtaccess tokens. - RFC 8693 token exchange, with a self-contained
CheckAudienceresource-server middleware. - Capability-scoped token triggers and a swappable
ClaimsResolver/ScopeRepository/ExchangePolicy. - Database-backed RS256 signing keys with a built-in rotation command and JWKS overlap.
Auth engine (optional)
- Package-owned login, registration, password reset, email verification, and password confirmation, driven by view and action seams your app fills.
- Multi-factor authentication: TOTP, recovery codes, and passkeys (WebAuthn).
- A post-login pipeline with a single decision hook (
requireMfa/deny/ add claims) andacr/amremission.
Requirements
- PHP
^8.5 - Laravel 13
- PostgreSQL 16 with the PHP
pdo_pgsqlextension - A UUID primary key on the application’s users table
- PHP
curlextension for back-channel logout delivery
Back-channel logout destinations must use HTTPS and resolve to public IP addresses. Private and internal destinations are rejected, and delivery requires cURL to pin the validated address for the request.
Installation
Before publishing or running migrations, the configured user model must use UUID identifiers.
The package’s user_id foreign keys are UUID columns and reference the users table configured
in oidc.migrations.users.table. In a new application, declare the user primary key with
$table->uuid('id')->primary() and add Laravel’s HasUuids trait to the user model.
For an existing application with integer user IDs, migrate its users and referencing columns
to UUIDs before installing this package; integer IDs are not supported.
composer require use-lock/server # Publish and run the migrations php artisan vendor:publish --tag=oidc-migrations php artisan vendor:publish --tag=passkeys-migrations php artisan migrate # Generate the first RSA signing key (stored in oidc_signing_keys) php artisan oidc:rotate-keys --if-missing # Optional: publish the config php artisan vendor:publish --tag=oidc-config
The service provider is auto-discovered. Set OIDC_ISSUER to your provider's public origin —
every URL advertised in discovery is derived from it.
The package includes login, registration, password reset, verification, consent, and MFA screens.
Configure authentication in config/oidc.php and UI options in config/oidc-ui.php.
PHP classes use the Lock\Server namespace;
UI classes live under each domain, such as Lock\Server\Authentication\Ui.
The consuming application's Lattice Vite plugin discovers the bundled frontend components. Publish UI customization files with:
php artisan vendor:publish --tag=oidc-ui-config php artisan vendor:publish --tag=oidc-ui-lang
Bind the authentication action contracts in your application and override view contracts in your service provider when you need custom screens.
A package-owned OAuth2 core
The package implements the OAuth 2.1 / OpenID Connect core itself: client authentication, the
authorization request, authorization codes with PKCE, refresh-token rotation, and the token
endpoint's grants live in the Protocol domain on top of the package's own tables and models.
This means:
- The authorization, token and approve/deny routes are registered by this package using its own
controllers, so
max_age,prompt, OIDC scopes and theid_tokenare wired in. - PKCE with
S256is required on every authorization request, per OAuth 2.1 §4.1.1/§7.6 — for confidential clients as well as public ones. A request missing it is answered with aninvalid_requesterror on the client's redirect URI. - Authorization codes and refresh tokens are opaque, single-use database records. A replayed code or a reused refresh token revokes every token that descends from it.
- The signing key is read on every request, so a key rotation takes effect without restarting the workers.
- No client-management JSON API ships with the package. Provision clients with
oidc:client, or through dynamic client registration.
Development
Run all commands from this repository's root:
composer install
# Start an isolated test database (Docker required)
docker run --detach --rm --name use-lock-server-tests \
-e POSTGRES_DB=use_lock_test -e POSTGRES_USER=use_lock -e POSTGRES_PASSWORD=use_lock \
-p 127.0.0.1:55432:5432 postgres:16
composer check
The defaults in phpunit.xml.dist connect to this PostgreSQL instance. Wait for
docker exec use-lock-server-tests pg_isready -U use_lock -d use_lock_test to succeed
before testing. Override DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, and
DB_PASSWORD to use another dedicated test database. The database user needs CREATEDB
for parallel tests, which create databases suffixed with _test_N. Test runs rebuild
the database schema; always use a dedicated test database. Stop the container with
docker stop use-lock-server-tests when finished.
Tests are split into two suites, with domain directories inside each suite:
tests/Unit: isolated component and architecture tests without a Laravel application or database. These cover JWK conversion and the exchange allowlist.tests/Feature: HTTP endpoints, authentication flows, UI responses, persistence, filesystem operations, and framework integration.
Pest assigns tests/FeatureTestCase.php to Feature. It boots Testbench,
refreshes the database, installs fixture signing keys, and prevents stray HTTP requests.
Unit tests use Pest's default PHPUnit test case. Shared test support lives in tests/Support; Pest automatically loads shared helpers from tests/Helpers.php.
UI response and component assertions belong in Feature.
Run a suite with composer test:unit or composer test:feature.
composer test runs all suites.
composer check runs Pint, PHPStan, Rector, and the full Pest suite with immutable
dates (CarbonImmutable). php artisan boots the local Testbench workbench.
Runtime code lives in src/, UI definitions in each domain's Ui/ directory, and package assets
in config/, database/, resources/, and routes/. Setup and consumer testing helpers
live under src/Support/.
See CONTRIBUTING.md for contribution and verification requirements, and SECURITY.md for private vulnerability reporting and supported versions.
License
MIT. See LICENSE.