Skip to content
laranailPublic

About

Re-usable authentication package

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

laranail/authkit

Tests Static analysis License MIT

laranail/authkit is not published to Packagist, so there is no registry-version badge to show: see Install.

Headless authentication for Laravel 13+. Ships the REST API; no views and no web routes.

Warning

This package is still in development. Breaking changes are imminent; use it in production at your own risk.

  • Fortify-backed — password reset, profile updates, password updates, email verification, passkeys, login throttling
  • Extensible API tokens — Sanctum is the default IssueTokenForUser backend; optional packages can register additional token issuers
  • Composable — separate actions for credential check vs session login

Requirements

PHP 8.4+ / Laravel 13.x

Install

laranail/* packages resolve through git, not Packagist. Add the repositories block to your application's composer.json — Composer ignores a dependency's own repositories, so it must list the whole transitive closure:

"repositories": [
    { "type": "vcs", "url": "https://github.com/laranail/authkit.git" },
    { "type": "vcs", "url": "https://github.com/laranail/console.git" },
    { "type": "vcs", "url": "https://github.com/laranail/enumerator.git" },
    { "type": "vcs", "url": "https://github.com/laranail/package-tools.git" },
    { "type": "vcs", "url": "https://github.com/laranail/captcha.git" },
    { "type": "vcs", "url": "https://github.com/laranail/db-tools.git" }
]

Then:

composer require laranail/authkit
php artisan vendor:publish --tag=laranail::authkit-config

See installation for the full walkthrough.

Quick start guide and usage

Getting started

  1. The guard defaults to web. To use another one, set it in .env:

    AUTHKIT_GUARD=web
  2. Publish and run only the migrations for the features you enable:

    php artisan vendor:publish --tag=laranail::authkit-passkey-migrations
    php artisan vendor:publish --tag=laranail::authkit-two-factor-migrations
    php artisan migrate

Usage

use Illuminate\Http\Request;
use Simtabi\Laranail\AuthKit\Contracts\AttemptEmailPasswordLoginInterface;
use Simtabi\Laranail\AuthKit\Contracts\LoginUserInterface;
use Simtabi\Laranail\AuthKit\Enums\AuthStatus;

public function store(Request $request, AttemptEmailPasswordLoginInterface $attempt, LoginUserInterface $login)
{
    $result = $attempt->execute(request: $request, guard: 'web');

    return match ($result->status) {
        AuthStatus::Passed    => tap(redirect()->intended('/dashboard'), fn () => $login->execute($result->user, 'web')),
        AuthStatus::Failed    => back()->withErrors(['email' => 'Invalid credentials.']),
        AuthStatus::Throttled => abort(429),
    };
}

Issue an API token instead of a session:

use Simtabi\Laranail\AuthKit\Contracts\IssueTokenForUserInterface;

$token = app(IssueTokenForUserInterface::class)->execute($user, name: 'mobile');
// $token->token — the plain-text token, shown once

The full walkthrough is in Getting started; everything else is in the documentation index.

Documentation

Full documentation: https://opensource.simtabi.com/documentation/laranail/authkit/

Guides

  • Installation — requirements, the repositories block, publishing config
  • Getting started — authenticate a user with the core alone
  • Configuration — guard, rate limits, and Fortify features
  • Architecture — layering, what is delegated to Fortify, the extension seams
  • Security — the guarantees this package makes and the ones it does not
  • Release — versioning, tagging, and ordering across the family

Reference

Project

Configuration

.env:

AUTHKIT_GUARD=web
AUTHKIT_RATE_LIMIT_MAX_ATTEMPTS=5
AUTHKIT_RATE_LIMIT_DECAY_MINUTES=1

config/laranail/authkit.php:

return [
    'guard' => env('AUTHKIT_GUARD', 'web'),

    'rate_limit' => [
        'max_attempts'  => (int) env('AUTHKIT_RATE_LIMIT_MAX_ATTEMPTS', 5),
        'decay_minutes' => (int) env('AUTHKIT_RATE_LIMIT_DECAY_MINUTES', 1),
    ],

    'fortify' => [
        'views'    => false,
        'features' => ['reset-passwords', 'update-profile-information', 'update-passwords', 'email-verification', 'passkeys'],
    ],
];

Remove passkeys from laranail.authkit.fortify.features to disable Fortify's passkey routes. Auth Kit only enables and configures Fortify; passkey ceremonies, responses, and persistence remain provided by Fortify and laravel/passkeys.

Security defaults

  • TOTP two-factor authentication is opt-in. See the TOTP setup and API flow.
  • Before production, configure HTTPS, secure session cookies, a working mail transport, and Turnstile keys when bot protection is enabled.

Passkeys

Passkey support uses Fortify's native integration with laravel/passkeys. It is stateful and requires the consuming application's authenticatable model to implement Fortify's PasskeyUser contract and use Auth Kit's morph-aware PasskeyAuthenticatable trait:

use Laravel\Fortify\Contracts\PasskeyUser;
use Simtabi\Laranail\AuthKit\PasskeyAuthenticatable;

class User extends Authenticatable implements PasskeyUser
{
    use PasskeyAuthenticatable;
}

The published migration stores ownership in passkeyable_type and passkeyable_id, so the same passkey implementation can be used by users, admins, or another authenticatable model. Auth Kit configures its morph-aware Passkey model for Fortify and retains the vendor package's WebAuthn actions, controllers, responses, and credential validation.

Publish Auth Kit's passkeys migration in the consuming application and run it:

php artisan vendor:publish --tag=laranail::authkit-passkey-migrations
php artisan migrate

Do not publish Fortify's migration tag for passkeys; Auth Kit owns this table migration while Fortify and laravel/passkeys provide the model and WebAuthn behavior.

Configure the relying party and allowed browser origins in config/fortify.php. The defaults use the host and URL from APP_URL; set them explicitly for production HTTPS domains when necessary:

'passkeys' => [
    'relying_party_id' => parse_url(config('app.url'), PHP_URL_HOST),
    'allowed_origins'   => [config('app.url')],
    'user_handle_secret' => env('PASSKEYS_USER_HANDLE_SECRET', config('app.key')),
    'timeout' => 60000,
],

Fortify's passkey management routes honor the fortify-options.confirmPassword setting and the passkeys rate limiter in fortify.limiters. Passkey login and confirmation require the configured stateful guard and session, so Auth Kit does not expose equivalent Sanctum API endpoints.

The browser ceremony is application-owned. Install the official client and connect it to Fortify's canonical route names; Auth Kit does not bundle JavaScript or a build pipeline:

npm install @laravel/passkeys

The application client should use Fortify's /passkeys/login/options, /passkeys/login, /passkeys/confirm/options, /passkeys/confirm, /user/passkeys/options, /user/passkeys, and /user/passkeys/{passkey} endpoints. Keep the browser origin, relying-party ID, and APP_URL aligned or WebAuthn validation will fail.

Actions

Action Purpose
AttemptEmailPasswordLogin Verify email + password against a guard, returns AuthResult
LoginUser Log user into session + regenerate session
LogoutUser Log out + invalidate session
CreateNewUser Validate and create user (Fortify CreatesNewUsers)
ResetUserPassword Validate and reset password (Fortify ResetsUserPasswords)
UpdateUserProfileInformation Validate and update profile (Fortify UpdatesUserProfileInformation)
UpdateUserPassword Validate and update password (Fortify UpdatesUserPasswords)
IssueTokenForUser Issue a token using the configured backend, returns TokenResult
CheckEmailExists Check if email is registered
FindUserByEmail Retrieve user by email

Result types

AuthResult — returned by login actions:

AuthResult::passed($user)   // credentials valid
AuthResult::failed()        // credentials invalid
AuthResult::throttled($seconds)  // rate limited

Check with $result->isPassed() or match on $result->status (AuthStatus::Passed|Failed|Throttled).

TokenResult — returned by IssueTokenForUser:

new TokenResult(user: $user, token: $token)

Abstract controllers

Extend these to wire up your own routes. JSON responses are handled automatically.

Controller Overridable methods
AbstractAttemptEmailPasswordLoginController passed(), failed(), throttled()
AbstractCheckEmailExistsController respond()
AbstractLogoutController loggedOut()
AbstractRegisterController registered()

Social login

Social login is maintained in laranail/authkit-social-login, which extends this package. See its social login guide for installation, providers, routes, persistence, and account-linking behavior.

Usage

Session login (web)

$result = app(AttemptEmailPasswordLogin::class)->execute(
    request: $request,
    guard: 'web',
);

if (! $result->isPassed()) {
    return back()->withErrors(['email' => 'Invalid credentials']);
}

app(LoginUser::class)->execute($result->user, guard: 'web');
return redirect()->intended('/dashboard');

API token

$tokenResult = app(IssueTokenForUser::class)->execute(
    user: $user,
    name: 'api-token',
);

return response()->json([
    'token' => $tokenResult->token,
    'user'  => $tokenResult->user,
]);

Sister packages

Package Role
laranail/authkit Headless core — actions, contracts, result objects, REST API
laranail/authkit-preset Blade scaffolding on top of the core
laranail/authkit-social-login Social login through Socialite
laranail/authkit-sso SAML 2.0 and OIDC single sign-on
laranail/authkit-oauth OAuth server, apps and scopes
laranail/authkit-tenancy Multi-tenancy
laranail/authkit-ldap LDAP and Active Directory

The family shares one root namespace, Simtabi\Laranail\AuthKit\, with each sibling a segment under it.

Contributing and security

See CONTRIBUTING.md. Report security issues privately — SECURITY.md.

License

MIT

About

Re-usable authentication package

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages