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

Sdk Laravel Package

twofas/sdk

PHP SDK for integrating 2FAS two-factor authentication into your applications. A lightweight client with straightforward configuration and clean, framework-friendly APIs for adding an extra layer of account security to Laravel and other PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

twofas/sdk is a plain PHP HTTP client, not a Laravel package. There is no auto-discovery, no ServiceProvider, no config/twofas.php to publish, and no facade. You wire it up yourself. Before writing any code, read these three things in order:

  1. README.md — the only source of truth for endpoint names and the auth model (expect a bearer token or API key).
  2. src/ — find the concrete client class and any Resources/ or Endpoints/ namespace. That is your public surface.
  3. src/Exceptions/ — the exception hierarchy you will catch in jobs and controllers.

Install and make a first call in a tinker session (do not go straight into application code until you have seen a real payload):

composer require twofas/sdk
use TwoFas\Sdk\Client; // confirm the real FQCN in src/ first

$client = new Client(token: env('TWOFAS_TOKEN'));
$response = $client->/* call the resource method shown in README */();
dump($response);

The realistic first use case is a timeboxed spike: authenticate against 2fas.com on a test account, pull one resource, and dump the raw response to a fixture file. Whatever you learn from that payload shapes everything downstream — the DTOs you build, the fakes you write, and whether this package survives the spike at all. Given zero stars and zero dependents you are the first serious user; treat the first hour as reconnaissance, not integration.

If the spike succeeds, land a config/services.php entry (not a new config file — keep it consistent with how you configure Stripe, Mailgun, etc.):

'twofas' => [
    'token'   => env('TWOFAS_TOKEN'),
    'base_uri' => env('TWOFAS_BASE_URI', 'https://api.2fas.com'),
    'timeout' => env('TWOFAS_TIMEOUT', 5),
],

Implementation Patterns

Wrap it behind a domain interface. Never let the SDK's DTOs or HTTP semantics reach controllers, jobs, or auth guards. Define a narrow interface describing what your domain needs and bind a concrete adapter in AppServiceProvider:

interface TwoFactorVendorClient
{
    public function listDevices(string $userId): array;
    public function exportBackups(string $userId): array;
}

final class TwoFasAdapter implements TwoFactorVendorClient
{
    public function __construct(private \TwoFas\Sdk\Client $client) {}

    public function listDevices(string $userId): array
    {
        $raw = $this->client->devices($userId); // method name per README
        return array_map(fn ($d) => DeviceDto::fromApi($d), $raw);
    }
}

Config-singleton binding. Bind the SDK client itself as a singleton so a single process reuses one HTTP connection pool, but bind the adapter per-request:

$this->app->singleton(\TwoFas\Sdk\Client::class, fn () =>
    new \TwoFas\Sdk\Client(
        token: config('services.twofas.token'),
        baseUri: config('services.twofas.base_uri'),
    )
);
$this->app->bind(TwoFactorVendorClient::class, TwoFasAdapter::class);

Push vendor calls to jobs, not the request cycle. Anything sync-flavoured (backup import, device enumeration, audit export) belongs on a queue. Wrap the adapter in a job with $tries = 1 at the SDK boundary and let your own retry policy sit on the job, not on the raw client.

Test with a fake, not HTTP fakes. Because the SDK is a thin wrapper over Guzzle/PSR-18, Http::fake() will not intercept it in every configuration. Bind a FakeTwoFactorClient in tests/TestCase.php for unit tests, and reserve contract tests (against recorded fixtures) for the adapter itself:

$this->swap(TwoFactorVendorClient::class, new FakeTwoFactorClient([
    'devices' => [$this->deviceFixture('iphone')],
]));

Contract fixtures are your regression net. After the spike, save one request and one response per endpoint you use into tests/fixtures/twofas/. The adapter test replays those through the SDK and asserts your DTOs. When the vendor silently changes shape, the adapter test fails before the incident reaches production.

Integration sequencing that actually works. Spike → interface + adapter → fake + fixtures → feature-flag behind a per-tenant config → canary one release → wider. Do not skip the flag; if the vendor goes down you want an env var flip, not a rollback.

Gotchas and Tips

  • No semver, no releases. Pin to a commit hash ("twofas/sdk": "dev-main#<sha>") and commit the lockfile. Do not float on main unless you want surprise breakage on composer update.
  • Guzzle version conflict risk. The SDK will pull in guzzlehttp/guzzle and psr/http-client. Laravel 10/11 already constrain these; run composer why guzzlehttp/guzzle before requireing, or you will discover the conflict halfway through a PR. Consider forking the transport layer to Illuminate\Support\Facades\Http so you inherit Laravel's retry, timeout, and observability conventions.
  • Do not put this in the authentication hot path. An SDK for 2fas.com is not a TOTP verifier for your own users. If a synchronous call is on the login critical path, a vendor outage becomes your outage. Keep it off the request cycle entirely, or wrap it with a circuit breaker (Laravel's Http::retry won't reach it, so do it manually).
  • Credentials and rotation. There is no documented rotation procedure. Store the token in your secret manager, not .env in prod, and write down "how do we rotate this" in the runbook before the first deploy. Assume the SDK does not handle rotation for you.
  • Rate limits are unknown. Assume per-key throttling and put a RateLimiter::for('twofas') in front of the adapter. Unbounded retries against an undocumented endpoint is how you get IP-banned.
  • Never store plaintext seeds. 2FAS backups are client-side encrypted with a user passphrase; the API presumably moves ciphertext. If any code path decrypts on your servers, stop and escalate — that is a product decision, not an engineering one to optimise.
  • Timeout budget. Set a hard timeout ≤ 5s at the client and ≤ 800ms if you ever call it inline. Guzzle defaults are generous; the SDK may not expose a timeout constructor arg, in which case you configure it via the injected HTTP client.
  • Read the exceptions carefully. A single-maintainer SDK may throw \RuntimeException rather than a typed exception for API errors. Grep src/ for throw new before you write catch blocks — you will be surprised.
  • Extend at the adapter, not the SDK. If you need observability, logging, or metrics, add them to TwoFasAdapter. Subclassing the SDK couples you to its internals and will break on every upstream change.
  • Health signal. Add a twofas:ping artisan command that calls a trivial endpoint and exits non-zero on failure. Wire it into your uptime check so silent contract drift shows up as an alert, not a support ticket.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager