Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Authy Laravel Package

rinvex/authy

Rinvex Authy brings Twilio Authy two-factor authentication to Laravel, with user registration, phone verification, token validation, and middleware-ready workflows for securing logins and sensitive actions. It offers configurable setup and a simple API for managing Authy users.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package

    composer require rinvex/authy
    

    The service provider Rinvex\Authy\AuthyServiceProvider and facade Rinvex\Authy\Authy are auto-discovered on Laravel 5.5+.

  2. Publish and wire up config

    php artisan vendor:publish --tag=rinvex-authy:config
    

    This creates config/authy.php. The only meaningful key is the Authy production API key:

    AUTHY_KEY=your_api_key_here
    
  3. Get an API key from https://dashboard.authy.com → Applications → API Keys. Use the production key; use the sandbox key while developing.

  4. First use case — register a user and verify them:

    use Rinvex\Authy\Authy;
    
    $authyId = Authy::register($user->email, $user->phone, $user->country_code);
    $user->update(['authy_id' => $authyId]);
    
    // Later, on login:
    $response = Authy::verify($user->authy_id, $request->input('token'));
    

Read vendor/rinvex/authy/src/ first — it's a thin wrapper over the authy/php SDK, so the real API surface lives in Authy.php plus AuthyServiceProvider.php. Everything else in this assessment is grounded in those two files.

Implementation Patterns

Schema is yours. The package stores nothing in a database — you own the columns. The canonical additions to users are:

$table->string('authy_id')->nullable()->after('password');
$table->string('phone')->nullable();
$table->string('country_code', 4)->nullable();

Registration flow. Call Authy::register($email, $phone, $countryCode) after your user is persisted. The $sendSms argument (default true) fires an SMS token immediately. Wrap in a transaction-safe block: if Authy fails, roll back the user or mark them as 2FA-pending.

Login flow — two-step gate. Keep Authy::verify() out of your login controller and inside a middleware or a dedicated TwoFactorController. The pattern:

  • Password check → create a partial session (auth.2fa.pending = user_id).
  • Redirect to a /2fa/challenge route (guarded by guest).
  • Authy::verify($authyId, $token) → on success, Auth::loginUsingId() and session()->forget('auth.2fa.pending').

This keeps the password and 2FA surfaces separate and avoids re-auth loops.

Middleware guard. For routes that require an already fully authenticated user, a simple EnsureTwoFactorPassed middleware that checks session('auth.2fa.passed') is cleaner than calling Authy on every request. Never call the Authy API per-request — it's rate limited and slow.

Fallback delivery.

Authy::requestSms($user->authy_id);   // SMS
Authy::requestCall($user->authy_id);  // Voice call

Expose both behind a single "Resend code" button with a small cooldown (e.g. 60s) so you don't burn Authy's rate limits.

OneTouch approval. Authy::registerActivity($authyId, $data) tells Authy what the login is for (IP, browser, geolocation) so the OneTouch push shows context. Pair this with a webhook route that Authy calls on approve/deny — this is where most teams wire up push-based login.

Soft-delete / GDPR. Call Authy::delete($authyId) on user deletion. This is not automatic; if you skip it, stale users remain billable in Authy's dashboard.

Testing. In feature tests, bind a fake facade:

Authy::shouldReceive('verify')->once()->andReturn(['success' => true]);

Never hit the network in CI.

Gotchas and Tips

$phone must not include the country code. Authy expects +1 (415) 555-0123 split as $phone = "4155550123", $countryCode = "1". Passing "+14155550123" as $phone will register a broken user that receives no SMS. Strip leading +, 0, and formatting before calling register().

The verify response is an array, not a boolean. A successful verify() returns something like ['success' => true, 'message' => 'Token is valid']. Compare $response['success'] === true, and check Authy::getUserStatus($authyId) if you need to distinguish "invalid token" from "user is banned / deleted".

Exceptions are your friend — until they're not. Authy:: methods throw on transport/API errors (invalid API key, network failure, rate limit). Distinguish wrong token (a success: false response) from API failure (an exception) in your UI: the former re-prompts, the latter should alert ops and log out.

Config key is key, not api_key. The package reads config('authy.key'). If you copy code from other Authy tutorials you'll get Authy::setApiKey(...) — that's the raw authy/php SDK, not this wrapper. Set AUTHY_KEY and trust the service provider.

Sandbox testing has fixed tokens. Authy's sandbox key returns tokens like 0000000 (7 zeros) for phone ending 007, 1111111 for 111, etc. Real production codes won't work in sandbox. Keep AUTHY_KEY in .env per-environment and add AUTHY_KEY to .env.example.

This package is thin and lightly maintained (35 stars). Before upgrading Laravel majors, verify the facade's getFacadeAccessor() still resolves under the new container. Because the wrapper is ~2 files, pinning a fork or migrating directly to authy/php is a realistic exit path if you hit a wall — the surface area is register, verify, requestSms, requestCall, delete, registerActivity, getUserStatus.

Country codes are strings, not ints. "44" for UK, "1" for US/Canada, "61" for AU. If you store as INT, +-less codes like "44" work but zero-padded codes (rare) will silently shift — store as VARCHAR(4).

Rate limits bite at scale. Authy throttles SMS per phone number per hour. Cache last-send time per user (Cache::put("authy:last_sms:{$id}", now(), 3600)) and refuse resends within the window rather than relying on the API error.

Debugging tips. Add a temporary Log::debug($response) inside the two call sites — the response includes message and Authy's own error codes (e.g. 60008 = invalid token). Authy's error codes are documented only on their site, so log them raw and map them in one place (config/authy.php is a fine place to add a messages map).

Extension point. If you need richer flows (device binding, custom OneTouch callbacks, retry policies), extend the facade target rather than editing the vendor package:

$this->app->bind(\Rinvex\Authy\Authy::class, \App\Services\MyAuthy::class);

in your AppServiceProvider::register().

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource