Azure Key Vault Secrets (Java)
Securely store and manage secrets like passwords, API keys, and connection strings.
Installation
<dependency> <groupId>com.azure</groupId> <artifactId>azure-security-keyvault-secrets</artifactId> <version>4.9.0</version> </dependency>
Client Creation
import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.SecretClientBuilder; import com.azure.identity.DefaultAzureCredentialBuilder;
// Sync client SecretClient secretClient = new SecretClientBuilder() .vaultUrl("https://<vault-name>.vault.azure.net") .credential(new DefaultAzureCredentialBuilder().build()) .buildClient();
// Async client SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .vaultUrl("https://<vault-name>.vault.azure.net") .credential(new DefaultAzureCredentialBuilder().build()) .buildAsyncClient();
Create/Set Secret
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
// Simple secret KeyVaultSecret secret = secretClient.setSecret("database-password", "P@ssw0rd123!"); System.out.println("Secret name: " + secret.getName()); System.out.println("Secret ID: " + secret.getId());
// Secret with options KeyVaultSecret secretWithOptions = secretClient.setSecret( new KeyVaultSecret("api-key", "sk_live_abc123xyz") .setProperties(new SecretProperties() .setContentType("application/json") .setExpiresOn(OffsetDateTime.now().plusYears(1)) .setNotBefore(OffsetDateTime.now()) .setEnabled(true) .setTags(Map.of( "environment", "production", "service", "payment-api" )) ) );
Get Secret
// Get latest version KeyVaultSecret secret = secretClient.getSecret("database-password"); String value = secret.getValue(); System.out.println("Secret value: " + value);
// Get specific version KeyVaultSecret specificVersion = secretClient.getSecret("database-password", "<version-id>");
// Get only properties (no value) SecretProperties props = secretClient.getSecret("database-password").getProperties(); System.out.println("Enabled: " + props.isEnabled()); System.out.println("Created: " + props.getCreatedOn());
Update Secret Properties
// Get secret KeyVaultSecret secret = secretClient.getSecret("api-key");
// Update properties (cannot update value - create new version instead) secret.getProperties() .setEnabled(false) .setExpiresOn(OffsetDateTime.now().plusMonths(6)) .setTags(Map.of("status", "rotating"));
SecretProperties updated = secretClient.updateSecretProperties(secret.getProperties()); System.out.println("Updated: " + updated.getUpdatedOn());
List Secrets
import com.azure.core.util.paging.PagedIterable; import com.azure.security.keyvault.secrets.models.SecretProperties;
// List all secrets (properties only, no values) for (SecretProperties secretProps : secretClient.listPropertiesOfSecrets()) { System.out.println("Secret: " + secretProps.getName()); System.out.println(" Enabled: " + secretProps.isEnabled()); System.out.println(" Created: " + secretProps.getCreatedOn()); System.out.println(" Content-Type: " + secretProps.getContentType());
// Get value if needed
if (secretProps.isEnabled()) {
KeyVaultSecret fullSecret = secretClient.getSecret(secretProps.getName());
System.out.println(" Value: " + fullSecret.getValue().substring(0, 5) + "...");
}
}
// List versions of a secret for (SecretProperties version : secretClient.listPropertiesOfSecretVersions("database-password")) { System.out.println("Version: " + version.getVersion()); System.out.println("Created: " + version.getCreatedOn()); System.out.println("Enabled: " + version.isEnabled()); }
Delete Secret
import com.azure.core.util.polling.SyncPoller; import com.azure.security.keyvault.secrets.models.DeletedSecret;
// Begin delete (returns poller for soft-delete enabled vaults) SyncPoller<DeletedSecret, Void> deletePoller = secretClient.beginDeleteSecret("old-secret");
// Wait for deletion DeletedSecret deletedSecret = deletePoller.poll().getValue(); System.out.println("Deleted on: " + deletedSecret.getDeletedOn()); System.out.println("Scheduled purge: " + deletedSecret.getScheduledPurgeDate());
deletePoller.waitForCompletion();
Recover Deleted Secret
// List deleted secrets for (DeletedSecret deleted : secretClient.listDeletedSecrets()) { System.out.println("Deleted: " + deleted.getName()); System.out.println("Deletion date: " + deleted.getDeletedOn()); }
// Recover deleted secret SyncPoller<KeyVaultSecret, Void> recoverPoller = secretClient.beginRecoverDeletedSecret("old-secret"); recoverPoller.waitForCompletion();
KeyVaultSecret recovered = recoverPoller.getFinalResult(); System.out.println("Recovered: " + recovered.getName());
Purge Deleted Secret
// Permanently delete (cannot be recovered) secretClient.purgeDeletedSecret("old-secret");
// Get deleted secret info first DeletedSecret deleted = secretClient.getDeletedSecret("old-secret"); System.out.println("Will purge: " + deleted.getName()); secretClient.purgeDeletedSecret("old-secret");
Backup and Restore
// Backup secret (all versions) byte[] backup = secretClient.backupSecret("important-secret");
// Save to file Files.write(Paths.get("secret-backup.blob"), backup);
// Restore from backup byte[] backupData = Files.readAllBytes(Paths.get("secret-backup.blob")); KeyVaultSecret restored = secretClient.restoreSecretBackup(backupData); System.out.println("Restored: " + restored.getName());
Async Operations
SecretAsyncClient asyncClient = new SecretClientBuilder() .vaultUrl("https://<vault>.vault.azure.net") .credential(new DefaultAzureCredentialBuilder().build()) .buildAsyncClient();
// Set secret async asyncClient.setSecret("async-secret", "async-value") .subscribe( secret -> System.out.println("Created: " + secret.getName()), error -> System.out.println("Error: " + error.getMessage()) );
// Get secret async asyncClient.getSecret("async-secret") .subscribe(secret -> System.out.println("Value: " + secret.getValue()));
// List secrets async asyncClient.listPropertiesOfSecrets() .doOnNext(props -> System.out.println("Found: " + props.getName())) .subscribe();
Configuration Patterns
Load Multiple Secrets
public class ConfigLoader { private final SecretClient client;
public ConfigLoader(String vaultUrl) {
this.client = new SecretClientBuilder()
.vaultUrl(vaultUrl)
.credential(new DefaultAzureCredentialBuilder().build())
.buildClient();
}
public Map<String, String> loadSecrets(List<String> secretNames) {
Map<String, String> secrets = new HashMap<>();
for (String name : secretNames) {
try {
KeyVaultSecret secret = client.getSecret(name);
secrets.put(name, secret.getValue());
} catch (ResourceNotFoundException e) {
System.out.println("Secret not found: " + name);
}
}
return secrets;
}
}
// Usage ConfigLoader loader = new ConfigLoader("https://my-vault.vault.azure.net"); Map<String, String> config = loader.loadSecrets( Arrays.asList("db-connection-string", "api-key", "jwt-secret") );
Secret Rotation Pattern
public void rotateSecret(String secretName, String newValue) { // Get current secret KeyVaultSecret current = secretClient.getSecret(secretName);
// Disable old version
current.getProperties().setEnabled(false);
secretClient.updateSecretProperties(current.getProperties());
// Create new version with new value
KeyVaultSecret newSecret = secretClient.setSecret(secretName, newValue);
System.out.println("Rotated to version: " + newSecret.getProperties().getVersion());
}
Error Handling
import com.azure.core.exception.HttpResponseException; import com.azure.core.exception.ResourceNotFoundException;
try { KeyVaultSecret secret = secretClient.getSecret("my-secret"); System.out.println("Value: " + secret.getValue()); } catch (ResourceNotFoundException e) { System.out.println("Secret not found"); } catch (HttpResponseException e) { int status = e.getResponse().getStatusCode(); if (status == 403) { System.out.println("Access denied - check permissions"); } else if (status == 429) { System.out.println("Rate limited - retry later"); } else { System.out.println("HTTP error: " + status); } }
Secret Properties
Property Description
name
Secret name
value
Secret value (string)
id
Full identifier URL
contentType
MIME type hint
enabled
Whether secret can be retrieved
notBefore
Activation time
expiresOn
Expiration time
createdOn
Creation timestamp
updatedOn
Last update timestamp
recoveryLevel
Soft-delete recovery level
tags
User-defined metadata
Environment Variables
AZURE_KEYVAULT_URL=https://<vault-name>.vault.azure.net
Best Practices
-
Enable Soft Delete - Protects against accidental deletion
-
Use Tags - Tag secrets with environment, service, owner
-
Set Expiration - Use setExpiresOn() for credentials that should rotate
-
Content Type - Set contentType to indicate format (e.g., application/json )
-
Version Management - Don't delete old versions immediately during rotation
-
Access Logging - Enable diagnostic logging on Key Vault
-
Least Privilege - Use separate vaults for different environments
Common Secret Types
// Database connection string secretClient.setSecret(new KeyVaultSecret("db-connection", "Server=myserver.database.windows.net;Database=mydb;...") .setProperties(new SecretProperties() .setContentType("text/plain") .setTags(Map.of("type", "connection-string"))));
// API key secretClient.setSecret(new KeyVaultSecret("stripe-api-key", "sk_live_...") .setProperties(new SecretProperties() .setContentType("text/plain") .setExpiresOn(OffsetDateTime.now().plusYears(1))));
// JSON configuration secretClient.setSecret(new KeyVaultSecret("app-config", "{"endpoint":"https://...","key":"..."}") .setProperties(new SecretProperties() .setContentType("application/json")));
// Certificate password secretClient.setSecret(new KeyVaultSecret("cert-password", "CertP@ss!") .setProperties(new SecretProperties() .setContentType("text/plain") .setTags(Map.of("certificate", "my-cert"))));
Trigger Phrases
-
"Key Vault secrets Java", "secret management Java"
-
"store password", "store API key", "connection string"
-
"retrieve secret", "rotate secret"
-
"Azure secrets", "vault secrets"