rainwaves/lara-auth-suite

Laravel API auth suite: Sanctum tokens & session modes, password reset, and 2FA.

Maintainers

Package info

github.com/Magnificent-Big-J/lara-auth-suite

pkg:composer/rainwaves/lara-auth-suite

Statistics

Installs: 123

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.0.0 2026-04-24 08:36 UTC

README

Modern, flexible authentication for Laravel APIs & SPAs.

Plug-and-play authentication for Laravel 10/11/12/13, supporting both API token auth (Sanctum) and session-based auth for SPAs — with password resets, backend-enforced Two-Factor Authentication (Email OTP + TOTP), recovery codes, and full role/permission support.

Overview

Rainwaves/Lara Auth Suite gives you full authentication without writing boilerplate:

  • Token authentication for mobile apps or external APIs
  • Session authentication for SPAs (Vue / React / Inertia / Livewire)
  • Unified password reset flow
  • Two-Factor Authentication (Email OTP, Authenticator App)
  • TOTP replay-attack protection
  • Recovery codes for locked-out users
  • Automatic role & permission assignment (Spatie Permissions)
  • Feature-flag gating — enable only what you need

Ideal for:

  • SaaS platforms
  • Admin dashboards
  • Multi-tenant SPAs
  • Hybrid apps needing both tokens + sessions

Demo Applications

Backend (Laravel)

Reference backend implementation using the package:

https://github.com/Magnificent-Big-J/lara-auth-suite-demo

Frontend (Nuxt SPA)

Full SPA login + 2FA flow:

https://github.com/Magnificent-Big-J/lara-auth-suite-nuxt-demo

Features

Feature Status Description
Sanctum PAT login Done Token-based API authentication
Session authentication Done Laravel guard + CSRF protection
Password reset (email) Done Full reset flow with throttle
2FA: Email OTP Done Secure email verification codes
2FA: TOTP (Authenticator App) Done Google Authenticator / Authy / 1Password
2FA enforcement Done Enforced on protected routes (backend-driven)
TOTP replay protection Done last_used_counter prevents counter reuse
Recovery codes Done 8-code offline fallback for locked-out TOTP users
Security throttles Done Login/reset/2FA rate limiting
Pending auth manager Done Session-less state bridge during 2FA challenge
Feature flag gating Done Disable unused auth features at the route level
Trusted devices Planned Device remembering
Token/session/device mgmt Planned Revoke, audit

Requirements

Laravel PHP Sanctum
10 / 11 / 12 / 13 8.2 / 8.3 / 8.4 4.x / 5.x

Breaking Changes in v2.0.0

Read this section carefully before upgrading from v1.x.

Registration is disabled by default. registration.enabled now defaults to false. If you have not published authx.php, registration will be silently disabled after upgrading. Publish (or re-publish) the config and set enabled: true explicitly.

issue_token_on_register defaults to false. Token issuance on registration is now opt-in. Existing apps that relied on the true default must set this explicitly in their published config.

sendEmailOtp() no longer returns the OTP. The return type changed from string to void. The plaintext code must never escape the service layer. Any code that called sendEmailOtp() and used the return value must be updated.

ITokenAuthService interface type hint corrected. The interface previously imported Illuminate\Auth\Authenticatable (a trait). It now imports Illuminate\Contracts\Auth\Authenticatable (an interface). Custom implementations that bound to the old type hint must update their use statement.

Session is not started until 2FA passes. When 2FA is required, the session is now invalidated and the CSRF token regenerated before the challenge is issued. The session is only created after successful verification. Frontends that assumed a valid session existed during the challenge step must be updated.

SessionLoginResult::$channel is now a TwoFactorChannel enum. The field was previously a plain string. Code that compares the value using string literals must use the enum instead, e.g. TwoFactorChannel::Email.

New migration required. Run php artisan migrate after upgrading. The new migration adds last_used_counter to the two_factor_secrets table for TOTP replay protection.

Installation

composer require rainwaves/lara-auth-suite

Publish configuration:

php artisan vendor:publish \
  --provider="Rainwaves\\LaraAuthSuite\\LaraAuthSuiteServiceProvider" \
  --tag=authx-config

Run migrations:

php artisan migrate

Authentication Flow

Authentication decisions are enforced on the backend. Frontend clients do not decide authentication state.

  • Credentials are validated
  • If 2FA is required: the session is invalidated, a pending auth state is created, and an OTP/TOTP challenge is issued — the user is not logged in yet
  • After successful 2FA: the session is created, CSRF token is issued, and the user is fully authenticated
  • If 2FA is not required: the session is created and the user is fully authenticated immediately

This prevents:

  • Logged-in-but-unverified states
  • Session persistence before verification
  • Frontend-controlled security decisions
  • Password reset user enumeration
  • TOTP replay attacks

Usage

1. Login (Session Mode – SPA)

POST /auth/session/login

{
  "email": "admin@example.com",
  "password": "secret",
  "remember": true
}

Response (2FA required — session not yet active):

{
  "user": {},
  "requires_two_factor": true,
  "channel": "email"
}

Response (2FA not required):

{
  "user": {},
  "requires_two_factor": false
}

2. Login (Token Mode / API Clients)

POST /auth/login

{
  "email": "admin@example.com",
  "password": "secret"
}

Response (no 2FA):

{
  "token": "plain-text-token",
  "token_type": "Bearer",
  "abilities": ["*"]
}

Response (2FA required — token is null until verified):

{
  "token": null,
  "requires_two_factor": true,
  "channel": "totp",
  "pending_auth_id": "uuid"
}

3. Get Current User

GET /auth/me — requires session cookie or Authorization: Bearer <token>

4. Logout

Session: POST /auth/session/logout

Token: POST /auth/logout

5. Forgot Password

POST /auth/password/forgot

{ "email": "admin@example.com" }

6. Reset Password

POST /auth/password/reset

{
  "email": "admin@example.com",
  "token": "reset-token",
  "password": "newpassword",
  "password_confirmation": "newpassword"
}

Passwords are capped at 128 characters to prevent bcrypt/argon2 resource exhaustion.

Two-Factor Authentication

Two-Factor Authentication is:

  • Evaluated during login (backend only)
  • Enforced before session/token is issued
  • Protected against replay attacks (TOTP counter tracking)

Email OTP endpoints

POST /auth/session/2fa/email
POST /auth/session/2fa/verify-otp
POST /auth/session/2fa/disable

POST /auth/2fa/email
POST /auth/2fa/verify-otp
POST /auth/2fa/disable

Authenticator App (TOTP)

POST /auth/session/2fa/totp/enable
POST /auth/session/2fa/totp/verify

POST /auth/2fa/totp/enable
POST /auth/2fa/totp/verify

Recovery Codes

Used when a TOTP user has lost access to their authenticator app:

POST /auth/session/2fa/recovery
POST /auth/2fa/recovery

SMS-based OTP is intentionally excluded due to SIM-swap risk. 2FA management endpoints require the current password by default.

Configuration (config/authx.php)

use Rainwaves\LaraAuthSuite\Support\Enums\AuthMode;
use Rainwaves\LaraAuthSuite\Support\Enums\AuthFeature;
use Rainwaves\LaraAuthSuite\Support\Enums\TwoFactorChannel;

return [
    'route_prefix' => 'auth',
    'mode'         => AuthMode::Session->value, // session | token | both
    'user_model'   => null,
    'user_resource' => null,
    'debug_ping'   => false, // enable GET /auth/ping (disable in production)

    'frontend' => [
        'password_reset_url' => env('AUTHX_FRONTEND_RESET_URL', '/auth/reset-password'),
    ],

    'features' => [
        AuthFeature::PasswordReset->value,
        AuthFeature::TwoFactor->value,
        AuthFeature::Tokens->value,
        AuthFeature::Devices->value,
    ],

    '2fa' => [
        'channels'    => [TwoFactorChannel::Email->value, TwoFactorChannel::Totp->value],
        'enforcement' => 'optional', // off | optional | required
        'remember_device_days' => 30,
        'otp' => [
            'length'              => 6,
            'expiry_seconds'      => 180,
            'throttle_per_minute' => 5,
        ],
        'totp_digits'             => 6,
        'totp_period'             => 30,   // RFC 6238 default (seconds)
        'totp_window'             => 1,    // steps either side accepted (covers ±30s clock drift)
        'verification_ttl_seconds' => 600, // how long verified 2FA state is trusted for token users
        'recovery_codes_count'    => 8,
        'require_password_on_manage' => true,
    ],

    'tokens' => [
        'abilities' => ['*'],
    ],

    'throttle' => [
        'login'        => 5,
        'two_factor'   => 5,
        'reset'        => 5,
        'decay_seconds' => 60,
    ],

    'registration' => [
        'enabled'               => false,  // opt-in — disabled by default
        'issue_token_on_register' => false, // opt-in
        'default_roles'         => [],
        'default_permissions'   => [],
        'allow_self_assign_roles' => false,
        'allow_self_assign_permissions' => false,
        'rules' => [
            'name'       => ['required', 'string', 'max:255'],
            'email'      => ['required', 'string', 'email', 'max:255', 'unique:users,email'],
            'password'   => ['required', 'string', 'min:8', 'max:128', 'confirmed'],
            'roles'      => ['sometimes', 'array'],
            'roles.*'    => ['string'],
            'permissions' => ['sometimes', 'array'],
            'permissions.*' => ['string'],
        ],
    ],

    'permissions' => [
        'enabled' => true,
        'fail_open_when_tables_missing' => false,
    ],
];

Frontend Integration (SPA)

Frontend clients consume backend decisions. They do not determine authentication state.

The backend returns:

  • Whether 2FA is required
  • Which channel must be used
  • A pending_auth_id (token mode) to complete the flow
  • Whether the session/token is fully verified

Reference implementation: https://github.com/Magnificent-Big-J/lara-auth-suite-nuxt-demo

Roadmap

Version Feature
v1.0 Token + session auth, password reset
v1.1 Email OTP, TOTP, 2FA enforcement
v2.0 Security hardening, TOTP replay protection, recovery codes, Laravel 13
v2.x Trusted devices, session/token audit

Security

Report security issues privately to:

security@rainwaves.dev

Do not open a public GitHub issue for security vulnerabilities.

License

MIT © Rainwaves

Credits

Built by Rainwaves Security-first authentication for serious Laravel applications.