NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Every extension point is a contract bound per guard in config, or globally in the container:

ContractBound viaPurpose
ResolvesAccessTokenClaimstokens.claims_resolverresolve(Account, GuardConfig): AccessTokenClaims — email, permissions, extra claims.
CreatesAccountsregistration.creatorcreate(GuardConfig, NewAccountData): Account — registration and invitation acceptance.
ProvidesRegistrationRulesregistration.rulesrules(GuardConfig): array — host fields; only these keys reach the creator.
AssessesLoginRiskrisk.assessorassess(LoginRiskContext): RiskAssessment.
RendersQrCodecontainerotpauthSvg(uri, size): ?string (null never blocks enrolment).
NegotiatesLocalecontainernegotiate(Request, GuardConfig): ?string.
ChecksBreachedPasswordscontainerisBreached(password, GuardConfig): bool.
FingerprintsDevicescontainerfingerprint(SessionContext, GuardConfig): ?string.

Container defaults are bound with bindIf, so a binding in your own provider wins:

// App\Providers\AppServiceProvider::register()
use RoundlyConsulting\Auth\Contracts\ChecksBreachedPasswords;
use RoundlyConsulting\Auth\Contracts\FingerprintsDevices;

$this->app->bind(ChecksBreachedPasswords::class, MyBreachChecker::class);
$this->app->bind(FingerprintsDevices::class, MyDeviceFingerprinter::class);

Models and resources

The four models may point at subclasses of the packaged ones — the subclass is the class created and queried everywhere. Any other class throws an InvalidConfigurationException naming the key; it never silently falls back to the packaged model. The JSON resources are non-final, and resources.account swaps the me resource per guard:

// config/authentication.php
'models' => [
    'challenge' => LoginChallenge::class,
    'one_time_token' => OneTimeToken::class,
    'invitation' => App\Models\Invitation::class,   // extends RoundlyConsulting\Auth\Models\Invitation
    'login_activity' => LoginActivity::class,
],

'guards' => [
    'users' => [
        'model' => App\Models\User::class,
        'resources' => ['account' => App\Http\Resources\CurrentUserResource::class],
    ],
],

Not extension points

The token formats (jwt, refresh-tokens), the two-factor and passkey ceremonies and the cryptographic primitives belong to the lower packages.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.