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

Vault Bundle Laravel Package

fourxxi/vault-bundle

fourxxi/vault-bundle integrates HashiCorp Vault with PHP applications, offering configuration and service wiring for secure secret retrieval and credential management. Keep sensitive values out of your codebase and access Vault-backed secrets through a simple, framework-friendly API.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. This bundle last shipped in January 2018. It targets Symfony 3.3–4.x and a pre-4.0 PHP style. Before you invest time, confirm it installs against your Symfony version:

composer require fourxxi/vault-bundle

If Composer refuses, you'll need to fork it, or accept that you're maintaining a private fork. For a day-to-day Vault integration on Symfony 5/6, the Vault HTTP API is small enough that wiring it yourself with symfony/http-client is often less work than resurrecting this bundle. Treat the bundle as a convenience wrapper over GET /v1/<path>, not as an abstraction you can't live without.

If you do install it:

  1. Register the bundle. Symfony 3.x: add new Fourxxi\Bundle\VaultBundle\FourxxiVaultBundle() to AppKernel. Symfony 4: add Fourxxi\Bundle\VaultBundle\FourxxiVaultBundle::class => ['all' => true] to config/bundles.php.

  2. Read the config source before writing config. The bundle's extension keys, defaults, and whether it expects a url/base_uri/address are defined in:

    vendor/fourxxi/vault-bundle/DependencyInjection/Configuration.php
    vendor/fourxxi/vault-bundle/DependencyInjection/FourxxiVaultExtension.php
    

    That second file tells you the literal service IDs and any aliases the bundle registers. Do not guess them.

  3. A plausible minimal config (verify against Configuration.php — key names have shifted across Vault bundles):

    # config/packages/fourxxi_vault.yaml
    fourxxi_vault:
        url: '%env(VAULT_ADDR)%'       # e.g. https://vault.internal:8200
        token: '%env(VAULT_TOKEN)%'    # a token with read on your paths
    
    VAULT_ADDR=https://vault.internal:8200
    VAULT_TOKEN=s.xxxxxxxxxxxxxxxx
    
  4. First use case — read a secret at runtime. The whole point is to stop putting credentials in parameters.yml/.env. Inject the client (find the exact service via the extension file or bin/console debug:container | grep -i vault) and read:

    use Fourxxi\Bundle\VaultBundle\Client\VaultClientInterface;
    
    class DatabaseCredentials
    {
        public function __construct(private VaultClientInterface $vault) {}
    
        public function get(): array
        {
            $response = $this->vault->read('secret/app/database');
            // structure depends on KV version; usually ['data' => [...]] on v2
            return $response['data'] ?? $response;
        }
    }
    

That is the 80% case: a service asks Vault for a credential, then hands it to a PDO/Redis/S3 client. Start there, not with container-time interpolation.

Implementation Patterns

Pattern 1 — Runtime read inside a service (preferred). Keep Vault reads lazy and close to the consumer. Wrap them so the rest of the app never sees the Vault response envelope:

final class VaultSecretReader
{
    public function __construct(private VaultClientInterface $client) {}

    public function fetch(string $path): array
    {
        try {
            return $this->client->read($path)['data'] ?? [];
        } catch (\Throwable $e) {
            throw new SecretNotFoundException("Vault read failed for {$path}", 0, $e);
        }
    }
}

Benefits: testable (mock the interface), survives Vault outages if you cache, and doesn't couple your DI graph to Vault's availability.

Pattern 2 — Deploy-time parameter resolution. If the bundle exposes an env-var processor (vault: prefix — check for a class implementing EnvVarProcessorInterface in the bundle), you can reference secrets from YAML/.env:

parameters:
    app.db_password: '%env(vault:secret/app/database:password)%'

This is convenient but drags a network dependency into cache:warmup. See Gotchas.

Pattern 3 — Cache the read, don't hammer Vault. Vault is not a low-latency KV store for every request. Combine the reader with a short-lived cache (PSR-6/PSR-16) keyed by path, TTL matched to lease_duration if you're reading dynamic secrets:

return $this->cache->get($key, function () use ($path) {
    return $this->reader->fetch($path);
});

For dynamic (leased) secrets like DB credentials from a Vault database secret engine, the TTL must be shorter than the lease or you'll serve dead credentials.

Pattern 4 — AppRole / Kubernetes auth if you have it. Static VAULT_TOKEN in env is a startup-only convenience. In production, tokens are short-lived. If the bundle only supports a static token (likely, given its age), plan to either (a) mint a token via AppRole/Kubernetes auth in a bootstrapping step and export it, or (b) call Vault's auth endpoints via HttpClient and hand the resulting token to the bundle. Do not run long-lived workers on a token that expires.

Pattern 5 — Per-environment Vault, per-environment paths. Point dev at a Vault dev server (vault server -dev), staging at a namespaced mount, prod at the real mount. Keep paths in configuration, not hardcoded in PHP:

parameters:
    vault.paths.database: 'secret/%kernel.environment%/database'

Integration tips

  • Register a thin wrapper interface (App\Vault\SecretReaderInterface) in front of the bundle's client so you can swap the bundle for an HttpClient implementation later without touching consumers.
  • Use debug:container and debug:config fourxxi_vault to confirm service IDs and resolved config early.
  • In tests, bind a fake VaultClientInterface returning canned responses; run one integration test against a real Vault dev container (docker hashicorp/vault) in CI.
  • If you read many secrets on boot, batch them in one service so failures surface once with a clear message, rather than as scattered 403s.

Gotchas and Tips

The package is effectively unmaintained. Zero dependents, last release 2018, 12 stars. Assume no bug fixes. Budget for a fork. If your team's security posture requires a maintained dependency, implement against the Vault HTTP API directly — the endpoints you need (/v1/<mount>/data/<path>, /v1/auth/approle/login) are a few dozen lines with symfony/http-client, and you control the code.

KV v1 vs KV v2 paths. The single most common failure. With KV v2 the read path is secret/data/app/db and the payload is {"data": {"data": {...}, "metadata": {...}}}. With KV v1 it's secret/app/db and {"data": {...}}. If your reads return null, check vault secrets list for the mount version. Normalize in your wrapper, not in every consumer.

Never bake the token into config. token: 's.abc...' in YAML ends up in git. Use %env(VAULT_TOKEN)% and ensure your .env isn't committed. Better: AppRole/Kubernetes auth in a bootstrap step.

Token TTL and lease expiry. A static token pasted into .env may be revoked or expired at deploy time. Long-running queue workers holding a token for hours or days are a hazard. If the bundle doesn't refresh, build token renewal outside it (a cron/command that re-auths) or keep token lifetimes aligned with process lifetimes.

Container compilation against a live Vault is fragile. If you wire secrets into parameters or an env processor, cache:clear/cache:warmup/container build now requires Vault reachability. That breaks on a fresh CI runner without network access, and it breaks your deploy if Vault is briefly down. Prefer runtime reads, or gate the compile-time fetch behind a check and fall back to a placeholder that fails loudly at first real use.

TLS and CA trust. Vault behind a private CA needs verify_peer/cafile config on whatever HTTP client the bundle uses. The bundle may not expose these options — another reason to check the extension file, and another reason to consider owning the HTTP layer. Vault dev mode is plain HTTP; production should never be.

Namespaces (Vault Enterprise) are likely unsupported. If you rely on X-Vault-Namespace, you probably need to add the header yourself via a client wrapper or fork.

Error semantics matter. A 404 means "path doesn't exist" (typo, wrong mount); a 403 means "token lacks permission" (policy problem); a 503 means "Vault is sealed." Catch and distinguish these — a blanket catch (\Exception) will send you chasing the wrong bug during an incident.

Debugging checklist when a read fails:

  1. curl -H "X-Vault-Token: $TOKEN" $VAULT_ADDR/v1/<path> — does it work outside Symfony? If not, it's a Vault/policy/path issue, not the bundle.
  2. bin/console debug:container <service-id> — is the service using the URL you think?
  3. bin/console debug:config fourxxi_vault — did your config key get picked up, or silently ignored?
  4. Is Vault sealed or unsealed? vault status.

Caching is your extension point. The bundle is thin; the most valuable thing you can add is a cache layer and a retry/timeout policy around it. If you need auth-method pluggability, HTTP option tuning, or KV versioning, fork and add it — upstream won't.

When to skip this bundle entirely. If you're on Symfony 5/6, or you need AppRole/Kubernetes auth, KV v2 ergonomics, namespace support, or a maintained dependency, don't fight the 2018 release. Write a 100-line VaultClient with symfony/http-client, register it as a service, and keep the same read()-style interface. You'll get modern PHP, full control, and no upgrade dead-end.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle