PHPackages                             skywalker-labs/passwordless - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. skywalker-labs/passwordless

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

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.

v2.1.0(3mo ago)61MITPHPPHP ^8.2CI passing

Since Feb 14Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/skywalker-labs/passwordless)[ Packagist](https://packagist.org/packages/skywalker-labs/passwordless)[ Docs](https://github.com/skywalker-labs/passwordless)[ GitHub Sponsors](https://github.com/sponsors/ermradulsharma)[ RSS](/packages/skywalker-labs-passwordless/feed)WikiDiscussions main Synced today

READMEChangelog (4)Dependencies (17)Versions (7)Used By (0)

Skywalker Passwordless — OTP &amp; Magic Link Authentication
============================================================

[](#skywalker-passwordless--otp--magic-link-authentication)

[![Version](https://camo.githubusercontent.com/b0295b714b93ddca88a4880c2686e994b4d06a4cda24b9f2f5870b31d7e1f168/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f736b7977616c6b65722d6c6162732f70617373776f72646c6573733f7374796c653d666f722d7468652d6261646765)](https://camo.githubusercontent.com/b0295b714b93ddca88a4880c2686e994b4d06a4cda24b9f2f5870b31d7e1f168/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f736b7977616c6b65722d6c6162732f70617373776f72646c6573733f7374796c653d666f722d7468652d6261646765)[![Total Downloads](https://camo.githubusercontent.com/44a2ff15d151c4fadae45427d8a38fddac297301b15cbccb6b2e425858c76612/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f736b7977616c6b65722d6c6162732f70617373776f72646c6573732e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/skywalker-labs/passwordless)[![PHPStan Level 9](https://camo.githubusercontent.com/1e1a4f0408dd61b01dde0d7c5a0a067d5a51764ea637d4625f7d4358bd09e1ac/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d4c6576656c253230392d627269676874677265656e2e7376673f7374796c653d666f722d7468652d6261646765)](https://phpstan.org)[![PHP Version](https://camo.githubusercontent.com/e202a9fb78bcbd0b5c20b8e5b094d43e502f17a774239954da750147f2cbb6ab/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e322d626c75652e7376673f7374796c653d666f722d7468652d6261646765)](https://www.php.net/)[![License](https://camo.githubusercontent.com/4ec140256e623b3b8fded9c1a3b72b274e91c7d544f385eac571e7140fd43fb3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f736b7977616c6b65722d6c6162732f70617373776f72646c6573732e7376673f7374796c653d666f722d7468652d6261646765)](LICENSE.md)[![Security Policy](https://camo.githubusercontent.com/fcb317cda612f7da01c58c35c7b3550abac315db012a79763db0b6b6191f8e6e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73656375726974792d706f6c6963792d627269676874677265656e2e7376673f7374796c653d666f722d7468652d6261646765)](SECURITY.md)

Elegant **passwordless authentication** for Laravel. Drop-in OTP login, 2FA enforcement, magic links, and backup codes — all built on [Skywalker Toolkit](https://github.com/skywalker-labs/toolkit) with action-oriented architecture, contract-based design, and **Extreme Strictness (PHPStan Level 9 + Strict Rules)** compliance.

---

✨ Features
----------

[](#-features)

FeatureDetail**OTP Login**Generate &amp; 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 &amp; 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
--------------

[](#-installation)

```
composer require skywalker-labs/passwordless
```

> **Requires:** PHP ≥ 8.2, Laravel ≥ 11.0

---

🛠️ Setup
--------

[](#️-setup)

### 1. Add the `HasOtp` Trait to Your User Model

[](#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 &amp; Migrations

[](#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`)

[](#3-configure-configpasswordlessphp)

```
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
-------

[](#-usage)

### Using the Facade

[](#using-the-facade)

```
use Skywalker\Otp\Facades\Otp;

// Send an OTP to an email or phone
$otp = Otp::generate('user@example.com');

// Verify the submitted OTP
try {
    Otp::verify('user@example.com', $request->otp);
} catch (\Skywalker\Otp\Exceptions\InvalidOtpException $e) {
    // Invalid or expired OTP
}
```

### Dependency Injection (Recommended)

[](#dependency-injection-recommended)

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);
}
```

### Magic Login Links

[](#magic-login-links)

```
// Generate a signed link valid for 15 minutes (configurable via 'expiry')
$link = Otp::generateMagicLink('user@example.com');
// → https://your-app.com/magic-login?identifier=...&signature=...

// Route: GET /magic-login  → passwordless.magic-login
// Validated automatically by hasValidSignature() in the controller
```

### Backup Codes

[](#backup-codes)

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

// Verify & consume a backup code (uses Hash::check internally)
$ok = Otp::verifyBackupCode('user@example.com', $submittedCode);
```

### Custom OTP Generator

[](#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

[](#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

[](#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
---------------

[](#️-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 ClassExtendsAll 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 &amp; Analysis
------------------------

[](#-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 &amp; Quality
------------------------

[](#-security--quality)

- **Extreme Strictness** — 100% compliance with PHPStan Level 9 + Strict &amp; 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
---------------------

[](#-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. &gt; 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
-------------------

[](#️-available-routes)

MethodURINameAuth`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
---------

[](#-license)

The MIT License (MIT). Please see [License File](LICENSE.md).

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance78

Regular maintenance activity

Popularity7

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Total

4

Last Release

115d ago

Major Versions

v1.2.0 → v2.0.02026-03-09

### Community

Maintainers

![](https://www.gravatar.com/avatar/68241409c48fd5184c979320937b363826a5a9aeeb4260e8d1fa753be39458b9?d=identicon)[ermradulsharma](/maintainers/ermradulsharma)

---

Top Contributors

[![ermradulsharma](https://avatars.githubusercontent.com/u/15956546?v=4)](https://github.com/ermradulsharma "ermradulsharma (28 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

laravelotpsecurityAuthentication2faloginPasswordlessskywalker

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/skywalker-labs-passwordless/health.svg)

```
[![Health](https://phpackages.com/badges/skywalker-labs-passwordless/health.svg)](https://phpackages.com/packages/skywalker-labs-passwordless)
```

###  Alternatives

[remotemerge/totp-php

Lightweight, fast, and secure TOTP (2FA) authentication library for PHP — battle tested, dependency free, and ready for enterprise integration.

2118.5k](/packages/remotemerge-totp-php)[lakm/nopass

Provides passwordless authentication for your laravel projects.

2215.9k3](/packages/lakm-nopass)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
