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

Http Auth Strategies Laravel Package

juststeveking/http-auth-strategies

A Laravel package offering reusable authentication strategy classes for HTTP requests, letting you encapsulate and swap Basic, Bearer, and custom auth schemes cleanly instead of scattering credentials through your code.

View on GitHub
Deep Wiki
Context7

Getting Started

Do the compatibility check before anything else. The last release is 2020-12-07 (v1.2.0). That predates Laravel 9/10/11 and PHP 8.1+. Run this first and stop if it fails:

composer require juststeveking/http-auth-strategies:^1.2 --dry-run
composer show juststeveking/http-auth-strategies   # read the requires block

Then install with an exact pin, never a floating constraint — this package touches credentials and has a single maintainer, 0 known dependents, and no release in years:

composer require juststeveking/http-auth-strategies:1.2.0

Where to look first. Read vendor/juststeveking/http-auth-strategies/src/ before writing a line of code. There are three things you need to confirm, because the surrounding documentation is thin and partly contradictory:

  1. The actual namespace and class names. Do not trust a blog post or the package description — use composer show and the src/ tree.
  2. The strategy contract. One method or two? Does it return a ['Authorization' => '...'] array, a raw header string, or a value you compose yourself? That single detail determines every usage pattern below.
  3. Inbound or outbound. The package description claims it reads and normalises inbound Authorization headers for Laravel apps. The surrounding assessments describe it as composing outbound headers for API clients. These are different packages. Resolve this with a five-minute spike against a real class before you design around either story — the outbound reading is the one consistent with the CustomStrategy release note, but verify rather than assume.

First use case. Pick exactly one vendor integration that already needs a non-standard header — an X-API-Key provider or a partner header — and nothing else. Write it once, by hand, with the simplest possible composition:

use JustSteveKing\HttpAuthStrategies\Strategies\CustomStrategy; // confirm namespace

$strategy = new CustomStrategy(
    name: 'X-API-Key',
    value: config('services.acme.key'),
);

Http::withHeaders($strategy->getHeaders())
    ->baseUrl(config('services.acme.url'))
    ->get('/v1/widgets');

If that reads cleanly, you have your pattern. If it feels like ceremony around a one-line array, you have your answer: use Http::withHeaders(['X-API-Key' => ...]) directly and skip the dependency. Do not adopt this package for Basic or Bearer auth — Http::withToken() and Http::withBasicAuth() already cover those in one line each.

Implementation Patterns

One named strategy per integration, resolved from config. The value of the package is that "what do we send to vendor X" has exactly one answer, in one auditable place. Keep a config/services.php-style block per integration listing the header name, the credential source, and the scheme, then build the strategy from that config. Resist the urge to build a generic "auth resolver" on top — with 8 stars and no maintenance, your abstraction should be a thin wrapper, not a framework.

Wrap, don't spread. Put each vendor behind a small client class that owns its own strategy instance and never leaks headers to callers:

final class AcmeClient
{
    public function __construct(private AuthStrategy $strategy) {}

    public function get(string $path, array $query = []): Response
    {
        return Http::withHeaders($this->strategy->getHeaders())
            ->baseUrl(config('services.acme.url'))
            ->retry(2, 200)
            ->get($path, $query);
    }
}

Bind it in a service provider. Controllers, jobs, and commands then call AcmeClient and never know a header exists. This is where the package earns its keep: swap the strategy in tests, and every call site inherits the change.

Bind as transients, not singletons. If a strategy resolves its secret in the constructor (vault, config(), an env read), a singleton() binding freezes that credential for the life of the worker. Under Octane that is a rotation bug that shows up hours later as a 401 on one host. Bind as bind() or resolve per request unless the secret is genuinely immutable.

Testability is the real payoff. Assert the exact outbound header set once per integration — this one test catches nearly every downstream auth regression:

Http::fake();

app(AcmeClient::class)->get('/v1/widgets');

Http::assertSent(fn ($req) => $req->hasHeader('X-API-Key', 'test-key')
    && ! $req->hasHeader('Authorization'));

Note the negative assertion. Half of auth bugs are headers being sent when they shouldn't be, or a second scheme riding along.

Custom HMAC and dated signatures fit CustomStrategy's shape if it accepts arbitrary names and values — compute the signature in a decorator, pass the result in. If it only takes a static name/value pair, keep the signing logic in your own class and use the package purely as a header-bag; do not fork it to add a sign() method to a package nobody maintains.

Keep an interface of your own in front of it. Declare an internal AuthStrategy contract you own and let the package's strategies implement or adapt to it. That single indirection is what lets you replace the dependency with ~100 lines of in-house code later without touching a single call site, and it insulates you if the upstream contract gained methods between versions.

Gotchas and Tips

Supply chain is the dominant risk, not features. 8 stars, 0 dependents, one maintainer, no release since 2020, and it handles credentials. Treat it as a pattern to copy, not a dependency to build deep on. Write the in-house fallback (~1–2 days) before you need it — and get a security review of header validation running concurrently with the spike, not after rollout.

Header injection is a real vector. If header names or values can be influenced by config or request data, CR/LF injection into the header line is exploitable. Constrain names to RFC 7230 token rules, reject control characters in values, and do not assume the package already does. Verify in src/, then add your own guard if it doesn't.

Header-name casing breaks tests, not servers. Header names are case-insensitive on the wire but case-sensitive in PHP arrays and in Http::assertSent. X-Api-Key vs X-API-Key passes in production and fails in CI, or vice versa. Pick one spelling per integration, put it in config, and let the test assert the same source of truth.

Ordering with Http is not commutative. ->withHeaders($headers)->withToken($token) and the reverse produce different final headers. If you combine the package's output with withToken/withBasicAuth, decide which one wins deliberately — a proxy sending a stale Authorization alongside a fresh X-API-Key is the classic symptom.

Never log the strategy output. Debug-level logging of outbound headers is genuinely the highest-leverage operational tool for "auth is failing but nothing is wrong" tickets — so log the header name, the host, the scheme, and whether a value was present. Never the value. Rotate-and-forget is not a recovery plan for a token in a log aggregator.

Secrets from env arrive with whitespace. A trailing newline in a rotated secret is the single most common false 401 and it is invisible in every diff. trim() at the boundary where you read the value, and write one test with a deliberately whitespace-padded secret.

Config caching kills closures. If you drive strategy selection from a config file, do not put closures or class instances in it — php artisan config:cache will fail or silently break. Store a class-string and resolve it from the container.

Make precedence deterministic and loud. With Basic, Bearer, and custom strategies coexisting, an ambiguous resolution order that still "works" is worse than one that throws — it can send the wrong credential to the wrong host. Fail fast on an unknown or missing strategy; never fall back to a default scheme.

Watch for stale-interface breakage on upgrade. A changelog line saying "new feature" does not mean the strategy interface didn't gain a method. If you have any in-house implementations, run your full test suite after every bump. Given the release cadence, there may never be another bump — which is itself the argument against deep coupling.

Scope discipline. This is not an auth server. It does not issue tokens, refresh OAuth2 authorization-code flows, handle consent, or authenticate your users. Record that boundary explicitly so a future "consolidation" effort doesn't fold inbound user identity into an unmaintained third-party package — that is a security review of an entirely different shape.

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