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

Laravel Version Endpoint Laravel Package

woweb/laravel-version-endpoint

woweb/laravel-version-endpoint adds a simple, configurable version endpoint to Laravel apps, making it easy to expose your application's current version for monitoring, deployment checks, and client integrations without writing custom routes.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer and publish its config:

composer require wowebnl/laravel-version-endpoint
php artisan vendor:publish --tag="version-endpoint-config"

Open the published config first — it is the whole contract of the package. You are looking for three things: the URI the endpoint is registered on, the shared secret used to sign requests, and the throttle value applied to signed calls. Set the secret from your environment (VERSION_ENDPOINT_SECRET or similar) rather than committing it; if the config reads env(...), remember php artisan config:cache in production.

Then check the package's route registration and its signature validation class. You need to know exactly what string is signed (path only? method + path? a timestamp? a body hash?) because your client has to reproduce it byte for byte. This is the single most important thing to read before writing any calling code.

The canonical first use case: a deploy pipeline or uptime monitor that asks "what version is actually running here?" without exposing version, commit SHA, or build metadata to the public internet. A signed GET returning 200 with the payload is your green light; anything else is a red light. As of v0.2.1 an unsigned or badly signed request is answered as if the path does not exist — a genuine router 404 through the exception handler — so probing the URL from a browser or a scanner gives an attacker nothing to distinguish it from a typo'd URL.

Start by calling it manually once, from php artisan tinker or a curl with a freshly computed signature, to confirm your signing implementation matches before wiring it into CI.

Implementation Patterns

Wrap signing in one place. Put the signature generation in a small class or an Http macro so every caller — CI, a scheduled command, a status page — uses identical logic. Something like:

Http::withHeaders(['X-Signature' => $signer->sign('GET', '/version')])
    ->get(config('version-endpoint.path'));

If you duplicate the signing logic in a shell script and a PHP test, one of them will drift the first time the package changes its canonical string.

Use it as a deployment gate. A post-deploy step that asserts a 200 and compares the returned commit to the one you just deployed catches the classic failure where the release never rolled out or opcache is serving a stale build. Treat any non-200 as a hard failure of the deploy, not a warning.

Distinguish "not found" from "not authorised" in your own tooling. Because the package deliberately collapses both into the same 404, your monitoring should assert on the success case only. Never build a check that says "if 404, the endpoint isn't installed" — that branch is exactly what the package is designed to make indistinguishable. Log the expected outcome and assert equality, not inequality.

Reuse the same signing helper for other internal endpoints. Once the signer exists, the pattern (HMAC over a canonical string, compared with hash_equals) is a good template for other internal-only routes, rather than reaching for a shared bearer token in a header.

Tune throttle to the caller, not the endpoint. Signed callers are limited per client address. Deploy checks, a status page poller, and an on-call engineer's laptop may all sit behind the same NAT egress, so budget the limit for the sum of your pollers rather than for one. Since v0.2.1 only signed requests consume the allowance, so scanners and bots hitting the URL can no longer starve your real callers — a good reason to keep the limit reasonably tight rather than disabling it.

In tests, use Http::fake() for your own client code, but keep at least one feature test that hits the real route with a real signature and one that hits it unsigned, asserting the 404 shape matches the framework's missing-page response. That second test is your regression guard for the behaviour introduced in 0.2.1.

Gotchas and Tips

A method outside the router's known set still leaks. v0.2.1 registers the route for every method the router knows and answers 404 for anything that is not a signed GET or HEAD. But a method the router does not know at all still yields 405, not 404. If concealing the endpoint matters to you, put a middleware in front of the router yourself — the package will not install one.

Your own fallback route can disagree with the package. If the application defines a catch-all fallback, a missing path goes there while an unsigned request to the version endpoint gets the exception handler's 404. The two responses can differ in status or JSON shape for every method. The payload is still behind the signature either way, but if you are relying on "looks identical to a missing page" as a property, verify it in your app rather than assuming it.

Signing mismatches are the number one support issue. The usual culprits: a trailing slash the client adds but the server's canonical string omits, a query string included on one side only, the HTTP method cased differently, or a timestamp component you forgot to include (or that has drifted past a tolerance window). When a call fails you get a 404 with no diagnostic, so debug by temporarily logging inside the validator rather than by staring at the response.

The failure mode is intentionally silent. There is no "invalid signature" log line and no 401. Do not add one permanently — the whole point is that the endpoint is invisible — but be aware that on-call engineers will otherwise waste time on what looks like a routing problem.

Rotating the secret breaks every caller at once. Update CI variables, status page config, and any other clients in the same change, or run two secrets side by side if the package supports a list. Nothing about the failure will tell you the secret is stale; you will just get 404s.

Configuration caches and long-running workers. After changing the path, secret, or throttle, run php artisan config:cache and restart queue workers and Octane/Swoole workers. A stale cached config is indistinguishable from a wrong signature.

HEAD is a signed success. If your monitoring issues HEAD probes, they are subject to the same signing requirement — an unsigned HEAD is now a 404, not a 200.

Rate limiting is keyed by client address. Behind a load balancer or proxy, make sure trusted proxies are configured so Laravel resolves the real client IP; otherwise every caller collapses into one bucket and a single noisy neighbour consumes everyone's allowance. Note that pre-0.2.1, unsigned traffic shared that same bucket and could exhaust it — if you were carrying a raised throttle value purely to survive scanner noise, you can probably lower it now.

Extension points are thin by design. The realistic levers are the config (path, secret, throttle) and what your application's version source reports. If you need extra fields, richer metadata, or environment gating, decorate the response from your own service rather than forking the package — the surface area is small enough that a fork becomes a maintenance burden fast.

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.
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
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core