LaravelPackages.net
Acme Inc.
Toggle sidebar
skywalker-labs/passwordless

Seamless Passwordless Authentication for Laravel. Integrate OTP (One-Time Password) Login and 2FA into your default authentication flow with zero-conf middleware and ready-to-use UI.

1
6
v2.1.0
About skywalker-labs/passwordless

skywalker-labs/passwordless is a Laravel package for seamless passwordless authentication for laravel. integrate otp (one-time password) login and 2fa into your default authentication flow with zero-conf middleware and ready-to-use ui.. It currently has 6 GitHub stars and 1 downloads on Packagist (latest version v2.1.0). Install it with composer require skywalker-labs/passwordless. Discover more Laravel packages by skywalker-labs or browse all Laravel packages to compare alternatives.

Last updated

Skywalker Passwordless β€” OTP & Magic Link Authentication

Version Total Downloads PHPStan Level 9 PHP Version License Security Policy

Elegant passwordless authentication for Laravel. Drop-in OTP login, 2FA enforcement, magic links, and backup codes β€” all built on Skywalker Toolkit with action-oriented architecture, contract-based design, and Extreme Strictness (PHPStan Level 9 + Strict Rules) compliance.


✨ Features

| Feature | Detail | |---|---| | OTP Login | Generate & verify time-limited one-time passwords | | Hashed Storage | OTPs and backup codes stored with Hash::make() β€” never plain-text | | Magic Login Links | Signed, temporary URLs for one-click authentication | | Backup Codes | Hashed emergency recovery codes | | Multi-Channel | Email, SMS (Twilio), Slack, and Log channels | | Event-Driven | OtpGenerated, OtpVerified, OtpFailed events for full extensibility | | Middleware Gate | otp.verified middleware with infinite-loop protection | | Rate Limiting | Built-in per-identifier request throttling on all routes | | Action Architecture | Each operation is a dedicated Action class (SRP) | | Extreme Strictness | 100% compliance with PHPStan Level 9 + Strict & Deprecation rules | | Zero-Trust Auth | Risk-based trust scoring (TrustEngine) integrated into the core flow | | Strict Types | declare(strict_types=1) and explicit type comparisons everywhere |


πŸ“¦ Installation

composer require skywalker-labs/passwordless

Requires: PHP β‰₯ 8.2, Laravel β‰₯ 11.0


πŸ› οΈ Setup

1. Add the HasOtp Trait to Your User Model

use Skywalker\Otp\Concerns\HasOtp;

class User extends Authenticatable
{
    use HasOtp;
}

The trait provides sendOtp(): string and verifyOtp(string $token): bool methods.

2. Publish Config & Migrations

php artisan vendor:publish --tag=passwordless-config
php artisan vendor:publish --tag=passwordless-migrations
php artisan migrate

3. Configure (config/passwordless.php)

return [
    'length'     => 6,            // OTP digit length
    'expiry'     => 10,           // Minutes until OTP expires
    'driver'     => 'cache',      // 'cache' or 'database'
    'channel'    => 'mail',       // 'mail' | 'log' | 'sms' | 'slack'
    'middleware' => ['web', 'throttle:6,1'],

    'services'   => [
        'twilio' => [
            'sid'   => env('TWILIO_SID'),
            'token' => env('TWILIO_AUTH_TOKEN'),
            'from'  => env('TWILIO_FROM'),
        ],
        'slack'  => [
            'webhook_url' => env('SLACK_WEBHOOK_URL'),
        ],
    ],
];

🎯 Usage

Using the Facade

use Skywalker\Otp\Facades\Otp;

// Send an OTP to an email or phone
$otp = Otp::generate('[email protected]');

// Verify the submitted OTP
try {
    Otp::verify('[email protected]', $request->otp);
} catch (\Skywalker\Otp\Exceptions\InvalidOtpException $e) {
    // Invalid or expired OTP
}

Inject the contract for testable, SOLID-compliant code:

use Skywalker\Otp\Domain\Contracts\OtpService;

public function __construct(private readonly OtpService $otp) {}

public function send(string $identifier): void
{
    $this->otp->generate($identifier);
}
// Generate a signed link valid for 15 minutes (configurable via 'expiry')
$link = Otp::generateMagicLink('[email protected]');
// β†’ https://your-app.com/magic-login?identifier=...&signature=...

// Route: GET /magic-login  β†’ passwordless.magic-login
// Validated automatically by hasValidSignature() in the controller

Backup Codes

// Generate 8 hashed recovery codes (stored securely in DB)
$codes = Otp::generateBackupCodes('[email protected]');
// Returns: ['AbcD123fGh', 'xYz987Qrst', ...]  ← shown once, stored hashed

// Verify & consume a backup code (uses Hash::check internally)
$ok = Otp::verifyBackupCode('[email protected]', $submittedCode);

Custom OTP Generator

use Skywalker\Otp\Facades\Otp;

// Use a custom generator at runtime (e.g. alphanumeric, UUID-style)
Otp::useGenerator(fn() => strtoupper(substr(md5(microtime()), 0, 6)));

Listen to Events

// In your EventServiceProvider or a Listener
use Skywalker\Otp\Events\OtpVerified;
use Skywalker\Otp\Events\OtpGenerated;
use Skywalker\Otp\Events\OtpFailed;

protected $listen = [
    OtpVerified::class  => [LogSuccessfulLogin::class],
    OtpGenerated::class => [NotifySecurityTeam::class],
    OtpFailed::class    => [AlertOnRepeatedFailures::class],
];

Middleware Gate

Add the otp.verified middleware to any route to enforce OTP verification before access:

Route::middleware(['auth', 'otp.verified'])->group(function () {
    Route::get('/dashboard', DashboardController::class);
});

The middleware automatically:

  • Skips users without the HasOtp trait
  • Allows access once otp_verified is set in the session
  • Excludes OTP verify routes to prevent redirect loops

πŸ—οΈ Architecture

The package follows a strict Action-Oriented + Domain-Driven architecture:

src/
β”œβ”€β”€ Actions/                    ← One class per operation (SRP)
β”‚   β”œβ”€β”€ GenerateOtp             ← Hash::make() + event dispatch
β”‚   β”œβ”€β”€ VerifyOtp               ← Hash::check() + timing-safe
β”‚   β”œβ”€β”€ GenerateBackupCodes     ← Hash::make() per code
β”‚   β”œβ”€β”€ VerifyBackupCode        ← Hash::check() against stored hashes
β”‚   └── GenerateMagicLink       ← Signed URL generation
β”œβ”€β”€ Concerns/
β”‚   └── HasOtp                  ← User model trait (sendOtp / verifyOtp)
β”œβ”€β”€ Domain/
β”‚   β”œβ”€β”€ Contracts/              ← OtpStore, OtpSender, OtpService interfaces
β”‚   └── ValueObjects/
β”‚       └── OtpToken            ← Immutable (readonly) value object
β”œβ”€β”€ Events/
β”‚   β”œβ”€β”€ OtpGenerated, OtpFailed, OtpVerified
β”œβ”€β”€ Exceptions/
β”‚   β”œβ”€β”€ OtpException            ← Extends PackageException (toolkit)
β”‚   β”œβ”€β”€ InvalidOtpException
β”‚   └── OtpDeliveryFailedException
β”œβ”€β”€ Facades/
β”‚   └── Otp                     ← Static access via Laravel facade
β”œβ”€β”€ Http/
β”‚   β”œβ”€β”€ Controllers/OtpAuthController  ← Injects OtpService contract
β”‚   └── Middleware/EnsureOtpVerified
β”œβ”€β”€ Infrastructure/
β”‚   β”œβ”€β”€ Delivery/NotificationSender    ← Multi-channel sender
β”‚   └── Persistence/
β”‚       β”œβ”€β”€ CacheOtpStore              ← driver=cache
β”‚       └── DatabaseOtpStore           ← driver=database
β”œβ”€β”€ Services/
β”‚   └── OtpService              ← Orchestrator, delegates to Actions
└── OtpServiceProvider.php      ← Bindings, routes, events, middleware

Toolkit foundation:

| Our Class | Extends | |---|---| | All 5 Action classes | Skywalker\Support\Foundation\Action | | OtpToken | Skywalker\Support\Foundation\ValueObject | | OtpException | Skywalker\Support\Exceptions\PackageException | | OtpService | Skywalker\Support\Foundation\Service | | OtpServiceProvider | Skywalker\Support\Providers\PackageServiceProvider |


πŸ§ͺ Testing & Analysis

# Run tests
composer test

# Static analysis (PHPStan Level 9)
composer analyse

# Mutation testing (Infection)
vendor/bin/infection

# Format code (Laravel Pint / PSR-12)
composer format

πŸ”’ Security & Quality

  • Extreme Strictness β€” 100% compliance with PHPStan Level 9 + Strict & Deprecation rules
  • Zero-Trust Security β€” Integrated TrustEngine for risk-based analysis
  • Hashed OTPs β€” stored with Hash::make(), verified with Hash::check()
  • Hashed Backup Codes β€” same approach as OTPs
  • Signed Magic Links β€” protection against link tampering
  • Rate Limiting β€” strict per-identifier request throttling
  • Strict Logic β€” no implicit type coercion, only explicit boolean comparisons

πŸ”’ Zero-Trust Security

This package integrates the Skywalker Trust Engine to provide risk-based authentication:

  1. Trust Scoring: Every authentication attempt calculates a "Trust Score" (0.0 to 1.0) based on IP, behavior, and environment.
  2. Adaptive 2FA: If a user has a very high trust score (e.g. > 0.8), the otp.verified middleware can be configured to bypass the OTP check (bypass_high_trust).
  3. Hijack Protection: If a session's trust score drops significantly mid-session, the user is automatically prompted for re-verification.
  4. Session Rotation: Sessions are regenerated upon successful OTP or Magic Link verification to prevent fixation attacks.

πŸ›£οΈ Available Routes

| Method | URI | Name | Auth | |---|---|---|---| | POST | /otp/send | otp.send | Public | | POST | /otp/verify | otp.verify | Public | | GET | /otp/verify | otp.verify.view | auth | | POST | /otp/verify-submit | otp.verify.submit | auth | | POST | /otp/resend | otp.resend | auth | | GET | /magic-login | passwordless.magic-login | Signed URL |


πŸ“„ License

The MIT License (MIT). Please see License File.

Comments