symfony / azure-keyvault-key-management
Symfony Azure Key Vault Key Management Bridge
Package info
github.com/symfony/azure-keyvault-key-management
Type:symfony-key-management-bridge
pkg:composer/symfony/azure-keyvault-key-management
Requires
- php: >=8.4.1
- symfony/http-client: ^7.4|^8.0
- symfony/key-management: ^8.2
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-05 05:59:14 UTC
README
Provides an implementation of Symfony\Component\KeyManagement\EncrypterInterface,
Symfony\Component\KeyManagement\DecrypterInterface and
Symfony\Component\KeyManagement\DataKeyGeneratorInterface backed by
Azure Key Vault (and
Managed HSM) over
its REST API. Encryption, decryption and data-key wrapping never expose the
master key: Azure performs them server-side.
This Bridge is experimental. Experimental features are not covered by Symfony's Backward Compatibility Promise.
use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\KeyManagement\Bridge\AzureKeyVault\AzureKeyVault; use Symfony\Component\KeyManagement\Bridge\AzureKeyVault\ClientCredentialsTokenProvider; $client = HttpClient::createForBaseUri('https://my-vault.vault.azure.net/'); $tokens = new ClientCredentialsTokenProvider( $client, $_SERVER['AZURE_TENANT_ID'], $_SERVER['AZURE_CLIENT_ID'], $_SERVER['AZURE_CLIENT_SECRET'], ); $kms = new AzureKeyVault($client, $tokens); // Use the key name for the latest version on writes, or append `/<version>` to select one. $ciphertext = $kms->encrypt('app-key', 'hello world'); $plaintext = $kms->decrypt($ciphertext); $dataKey = $kms->generateDataKey('app-key', 32); $result = $dataKey->use(fn (string $dek): string => /* local AEAD encrypt */);
Each new ciphertext and wrapped data key records the key version it was produced under, and the bridge checks that Azure's response names the requested key. Keep older key versions enabled while their ciphertexts or wrapped data keys must remain readable.
Authentication
Bring your own TokenProviderInterface to plug
any Azure AD flow: the bundled ClientCredentialsTokenProvider covers the
client_credentials grant (tenant id + client id + client secret) and caches
the token in memory until 60 seconds before its advertised expiration.
Managed Identity, Workload Identity, federated credentials, on-behalf-of, ...
are out of scope for the default provider; implement
TokenProviderInterface for your authentication flow.
Custom token providers implement invalidateToken($token) to discard a cached
token only when it matches the rejected value. If Key Vault responds with HTTP
401, the bridge obtains a new token and retries the request once if that token
differs. HTTP 403 is reported directly without invalidating the token.
Algorithms
The bridge accepts two configurable algorithms:
encryptAlgorithm(defaultRSA-OAEP-256): used byencrypt()/decrypt().RSA-OAEP,RSA1_5and the AEAD variantsA128GCM/A192GCM/A256GCMare also accepted (the AEAD variants require a symmetric key, available on Managed HSM or Key Vault Premium in preview).wrapAlgorithm(defaultRSA-OAEP-256): used bygenerateDataKey()andunwrapDataKey(). Same algorithm set as above; with a symmetric key you can useA128KW/A192KW/A256KWby setting it explicitly.
The DSN factory only accepts the algorithm names Azure Key Vault documents
(RSA-OAEP-256, RSA-OAEP, RSA1_5, the A*GCM, A*CBC, A*CBCPAD and
A*KW families) so that a typo does not surface later as a decryption
failure, which is how the decrypt path reports Azure's HTTP 400.
encrypt() / decrypt() go through the RSA path by default and are therefore
suited to small payloads (config secrets, tokens). For arbitrary-size
payloads, use Symfony\Component\KeyManagement\EnvelopeEncrypter on top of the bridge:
the master key only sees the wrapped DEK.
DSN scheme
azure-keyvault://<clientId>:<clientSecret>@<vault-name>.vault.azure.net?tenant=<tenantId>[&algorithm=...&wrap_algorithm=...&api_version=...&audience=...]
The host is the full vault DNS (<name>.vault.azure.net, or
<name>.managedhsm.azure.net for Managed HSM). The factory selects a Key Vault
or Managed HSM audience from the host, which audience can override, and it
always authenticates against the public Microsoft Entra authority. A sovereign
cloud (US government, China) needs another authority, so construct
AzureKeyVault there manually with a token provider configured for that cloud.
Examples:
azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-vault.vault.azure.net?tenant=TENANT_ID
azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-vault.vault.azure.net?tenant=TENANT_ID&algorithm=RSA-OAEP&api_version=7.4
azure-keyvault://CLIENT_ID:CLIENT_SECRET@my-hsm.managedhsm.azure.net?tenant=TENANT_ID&algorithm=A256GCM&wrap_algorithm=A256KW
AAD support
AEAD algorithms (A128GCM/A192GCM/A256GCM) accept Azure's aad
parameter natively and are integrity-protected. RSA algorithms have no AAD
concept; passing a non-empty $aad to an RSA-configured bridge raises
UnsupportedOperationException.
For AEAD ciphertexts, this bridge concatenates the algorithm, IV, tag and
value into a single dot-separated blob (<alg>.<iv>.<tag>.<value>, all
base64url) so callers can store one opaque ciphertext and let the bridge
recover its parts on decrypt. The pieces themselves are exactly what Azure
returns; nothing is added to or stripped from them.