padosoft/laravel-rebel-recovery

High-assurance account recovery for Laravel Rebel: single-use HMAC-hashed recovery (backup) codes, generated once at enrolment, with anti-ATO checks. Part of padosoft/laravel-rebel-*.

Maintainers

Package info

github.com/padosoft/laravel-rebel-recovery

pkg:composer/padosoft/laravel-rebel-recovery

Statistics

Installs: 50

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-06-03 11:30 UTC

This package is auto-updated.

Last update: 2026-06-03 12:24:58 UTC


README

Single-use recovery codes done right. Backup codes the user can fall back to when they lose their device — generated once, stored only as keyed HMACs, verified in constant time, single-use, and easy to type. Part of the padosoft/laravel-rebel-* suite.

Laravel Rebel

Laravel 12|13 PHP 8.3+ PHPStan max Pest 4 MIT

Table of contents

What it is

High-assurance account-recovery building blocks for Rebel. v0.1.0 ships recovery (backup) codes: a set of one-time codes a user can use to recover access. Pair them with a high-assurance step-up purpose (from laravel-rebel-step-up) to gate sensitive recovery flows.

Depends on padosoft/laravel-rebel-core.

Why this package

What In short
★★★ Hashed at rest Codes are stored as a keyed HMAC of (salt|code) with a key_version — never plaintext, pepper-rotation friendly.
★★★ Single-use & atomic Verification locks the row and consumes the code; a code works exactly once.
★★★ Constant-time verify All candidates are checked without early-exit, so timing doesn't leak which code matched.
★★ Typo-tolerant Input is normalized (case, separators, Crockford O→0 / I·L→1), so a correct code never fails on format.
★★ Regenerate safely Generating a new set invalidates all previous unconsumed codes.
★★ Audited & multi-tenant Generate/complete/fail are recorded; rows are tenant-scoped.

Rebel Recovery vs the alternatives

Capability Rebel Recovery Shopify Fortify recovery codes Hand-rolled
Self-issued recovery codes for your users
Codes hashed at rest (you control storage) ➖ (encrypted blob)
Keyed HMAC + key_version (pepper rotation)
Constant-time verification
Atomic single-use (row lock)
Input normalization (typo-tolerant)
~100-bit entropy codes ➖ (~50 bits)
Audited + multi-tenant (your app)

Legend: ✅ built-in · ➖ partial / hosted-only / not exposed to you · ❌ not available.

Note: Shopify is a hosted, closed commerce platform — its own staff/customer logins may have backup codes, but it never exposes a self-hostable, HMAC-hashed, single-use recovery-code API you can issue to your application's users.

Installation

composer require padosoft/laravel-rebel-recovery
php artisan vendor:publish --tag="rebel-recovery-migrations"
php artisan migrate

Usage

use Padosoft\Rebel\Recovery\RecoveryCodeManager;

$recovery = app(RecoveryCodeManager::class);

// At enrolment: generate and SHOW ONCE (cannot be retrieved again)
$codes = $recovery->generate($user, count: 10);
// → ["A1B2-C3D4-E5F6-G7H8-J9K0", ...]  display/download these now

// Later: the user submits one code to recover access
if ($recovery->verify($user, $request->string('code'))) {
    // consumed — let them through (ideally behind a high-assurance step-up)
}

$recovery->remaining($user); // how many codes are left

Security notes

  • Never stored in plaintext: only a keyed HMAC of (salt|code) with a key_version.
  • Single-use & atomic: a row lock guarantees a code can be redeemed once.
  • Constant-time: the whole candidate set is checked, no early-exit timing leak.
  • No built-in lockout: recovery codes are a lookup secret — put your app's brute-force throttle in front of verify() (and treat repeated failures as an anti-ATO signal).
  • Multi-tenant: rows are scoped via the core tenant scope — resolve the current tenant per request in multi-tenant deployments so codes never cross tenants.

.env.example

REBEL_RECOVERY_CODE_COUNT=10

Testing & License

composer test      # Pest (generate, single-use verify, reuse, regenerate, per-subject, normalization)
composer phpstan   # static analysis, level max
composer pint      # code style

License: MIT — see LICENSE. Part of the padosoft/laravel-rebel suite.