SDKs & Integrations
.NET SDK
Official .NET SDK for KeyEnv.
.NET SDK
Official .NET SDK for KeyEnv with .NET 6.0+ support and async/await patterns.
Beta Release: This SDK is currently in development. APIs may change before the stable 1.0 release.
Installation
NuGet Package Manager
dotnet add package KeyEnvPackage Manager Console
Install-Package KeyEnvPackageReference
Add to your .csproj:
<PackageReference Include="KeyEnv" Version="1.1.0" />Quick Start
using KeyEnv;
var client = KeyEnvClient.Create(Environment.GetEnvironmentVariable("KEYENV_TOKEN")!);
// Load secrets into environment variables
int count = await client.LoadEnvAsync("your-project-id", "production");
Console.WriteLine($"Loaded {count} secrets");
// Access secrets
Console.WriteLine(Environment.GetEnvironmentVariable("DATABASE_URL"));Initialize the Client
Simple Initialization
using KeyEnv;
var client = KeyEnvClient.Create(Environment.GetEnvironmentVariable("KEYENV_TOKEN")!);With Options
For more control, use KeyEnvOptions:
using KeyEnv;
var client = KeyEnvClient.Create(new KeyEnvOptions
{
Token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")!,
Timeout = TimeSpan.FromSeconds(60),
CacheTtl = TimeSpan.FromMinutes(5)
});Loading Secrets
Load into Environment Variables
The simplest way to use secrets in your application:
int count = await client.LoadEnvAsync("project-id", "production");
Console.WriteLine($"Loaded {count} secrets");
// Access via Environment.GetEnvironmentVariable
var dbUrl = Environment.GetEnvironmentVariable("DATABASE_URL");
var apiKey = Environment.GetEnvironmentVariable("API_KEY");Get Secrets as Dictionary
Get secrets as a key-value dictionary:
var secrets = await client.GetSecretsAsDictionaryAsync("project-id", "production");
Console.WriteLine(secrets["DATABASE_URL"]);
Console.WriteLine(secrets["API_KEY"]);Export as List
Get secrets with metadata:
var secrets = await client.GetSecretsAsync("project-id", "production");
foreach (var secret in secrets)
{
Console.WriteLine($"{secret.Key}={secret.Value}");
}Managing Secrets
Get a Single Secret
var secret = await client.GetSecretAsync("project-id", "production", "DATABASE_URL");
Console.WriteLine(secret.Value);
Console.WriteLine(secret.Description);Set a Secret
Creates or updates a secret:
await client.SetSecretAsync("project-id", "production", "API_KEY", "sk_live_...");
// With description
await client.SetSecretAsync(
"project-id",
"production",
"API_KEY",
"sk_live_...",
description: "Production API key"
);Delete a Secret
await client.DeleteSecretAsync("project-id", "production", "OLD_KEY");Bulk Operations
Bulk Import
Import multiple secrets at once:
using KeyEnv.Types;
var secrets = new List<SecretInput>
{
new SecretInput { Key = "DATABASE_URL", Value = "postgres://localhost/mydb" },
new SecretInput { Key = "REDIS_URL", Value = "redis://localhost:6379" },
new SecretInput { Key = "API_KEY", Value = "sk_test_...", Description = "Test API key" }
};
var result = await client.BulkImportAsync(
"project-id",
"development",
secrets,
new BulkImportOptions { Overwrite = true }
);
Console.WriteLine($"Created: {result.Created}, Updated: {result.Updated}");Generate .env File
var envContent = await client.GenerateEnvFileAsync("project-id", "production");
await File.WriteAllTextAsync(".env", envContent);Projects & Environments
List Projects
var projects = await client.ListProjectsAsync();
foreach (var project in projects)
{
Console.WriteLine($"{project.Name} ({project.Id})");
}Get Project Details
var project = await client.GetProjectAsync("project-id");
Console.WriteLine($"Project: {project.Name}");
foreach (var env in project.Environments)
{
Console.WriteLine($" - {env.Name}");
}List Environments
var environments = await client.ListEnvironmentsAsync("project-id");
foreach (var env in environments)
{
Console.WriteLine(env.Name);
}Environment Permissions
List Permissions
var permissions = await client.ListPermissionsAsync("project-id", "production");
foreach (var perm in permissions)
{
Console.WriteLine($"{perm.UserEmail}: {perm.Role}");
}Set Permission
await client.SetPermissionAsync("project-id", "production", "user-id", "write");Get My Permissions
var response = await client.GetMyPermissionsAsync("project-id");
foreach (var perm in response.Permissions)
{
Console.WriteLine($"{perm.EnvironmentName}: {perm.Role} (CanWrite: {perm.CanWrite})");
}
Console.WriteLine($"Is Team Admin: {response.IsTeamAdmin}");Caching
Enable caching for better performance in high-throughput applications:
var client = KeyEnvClient.Create(new KeyEnvOptions
{
Token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")!,
CacheTtl = TimeSpan.FromMinutes(5)
});
// First call fetches from API
await client.GetSecretsAsync("project-id", "production");
// Subsequent calls within TTL use cache
await client.GetSecretsAsync("project-id", "production");
// Clear cache when needed
client.ClearCache("project-id", "production");
client.ClearAllCache();Error Handling
using KeyEnv;
try
{
var secret = await client.GetSecretAsync("project-id", "production", "MISSING_KEY");
}
catch (KeyEnvException ex)
{
Console.WriteLine($"Error {ex.StatusCode}: {ex.Message}");
if (ex.IsNotFound)
{
Console.WriteLine("Secret not found");
}
else if (ex.IsUnauthorized)
{
Console.WriteLine("Invalid or expired token");
}
else if (ex.IsForbidden)
{
Console.WriteLine("Access denied");
}
}Cancellation Support
All async methods support cancellation tokens:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try
{
var secrets = await client.GetSecretsAsync("project-id", "production", cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled");
}IDisposable Pattern
The client implements IDisposable for proper resource cleanup:
using (var client = KeyEnvClient.Create(token))
{
await client.LoadEnvAsync("project-id", "production");
// Client is disposed when leaving the using block
}
// Or with using declaration (C# 8+)
using var client = KeyEnvClient.Create(token);
await client.LoadEnvAsync("project-id", "production");API Reference
Constructor Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
Token | string | Yes | - | Service token |
Timeout | TimeSpan? | No | 30s | Request timeout |
CacheTtl | TimeSpan? | No | 0 | Cache TTL (0 disables) |
BaseUrl | string? | No | https://api.keyenv.dev | API base URL |
Methods
| Method | Description |
|---|---|
GetCurrentUserAsync() | Get current user/token info |
ValidateTokenAsync() | Validate token and get user info |
ListProjectsAsync() | List all accessible projects |
GetProjectAsync(projectId) | Get project with environments |
CreateProjectAsync(teamId, name) | Create a new project |
DeleteProjectAsync(projectId) | Delete a project |
ListEnvironmentsAsync(projectId) | List environments in a project |
CreateEnvironmentAsync(projectId, name) | Create a new environment |
DeleteEnvironmentAsync(projectId, env) | Delete an environment |
ListSecretsAsync(projectId, env) | List secret keys (no values) |
GetSecretsAsync(projectId, env) | Export secrets with values |
GetSecretsAsDictionaryAsync(projectId, env) | Export as dictionary |
GetSecretAsync(projectId, env, key) | Get single secret |
SetSecretAsync(projectId, env, key, value) | Create or update secret |
DeleteSecretAsync(projectId, env, key) | Delete secret |
BulkImportAsync(projectId, env, secrets) | Bulk import secrets |
LoadEnvAsync(projectId, env) | Load secrets into environment |
GenerateEnvFileAsync(projectId, env) | Generate .env file content |
GetSecretHistoryAsync(projectId, env, key) | Get secret version history |
ListPermissionsAsync(projectId, env) | List permissions |
SetPermissionAsync(projectId, env, userId, role) | Set permission |
DeletePermissionAsync(projectId, env, userId) | Delete permission |
GetMyPermissionsAsync(projectId) | Get current user's permissions |
GetProjectDefaultsAsync(projectId) | Get default permissions |
SetProjectDefaultsAsync(projectId, defaults) | Set default permissions |
ClearCache(projectId, environment) | Clear specific cache |
ClearAllCache() | Clear all cached data |
Examples
ASP.NET Core Web API
// Program.cs
using KeyEnv;
var builder = WebApplication.CreateBuilder(args);
// Load secrets at startup
var keyEnvToken = Environment.GetEnvironmentVariable("KEYENV_TOKEN");
if (!string.IsNullOrEmpty(keyEnvToken))
{
using var client = KeyEnvClient.Create(keyEnvToken);
await client.LoadEnvAsync(
Environment.GetEnvironmentVariable("KEYENV_PROJECT")!,
builder.Environment.EnvironmentName.ToLower()
);
}
// Now secrets are available via Environment.GetEnvironmentVariable
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();ASP.NET Core with Dependency Injection
// Program.cs
using KeyEnv;
var builder = WebApplication.CreateBuilder(args);
// Register KeyEnvClient as a singleton
builder.Services.AddSingleton<KeyEnvClient>(sp =>
{
return KeyEnvClient.Create(new KeyEnvOptions
{
Token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")!,
CacheTtl = TimeSpan.FromMinutes(5)
});
});
var app = builder.Build();
app.Run();
// In a controller
[ApiController]
[Route("api/[controller]")]
public class SecretsController : ControllerBase
{
private readonly KeyEnvClient _keyEnv;
public SecretsController(KeyEnvClient keyEnv)
{
_keyEnv = keyEnv;
}
[HttpGet]
public async Task<IActionResult> Get()
{
var secrets = await _keyEnv.GetSecretsAsDictionaryAsync("project-id", "production");
return Ok(new { count = secrets.Count });
}
}Console Application
using KeyEnv;
class Program
{
static async Task Main(string[] args)
{
var token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")
?? throw new InvalidOperationException("KEYENV_TOKEN not set");
using var client = KeyEnvClient.Create(token);
// Load all secrets into environment
var count = await client.LoadEnvAsync("my-project", "production");
Console.WriteLine($"Loaded {count} secrets");
// Use the secrets
var dbUrl = Environment.GetEnvironmentVariable("DATABASE_URL");
Console.WriteLine($"Database: {dbUrl}");
}
}Azure Functions
using KeyEnv;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddSingleton<KeyEnvClient>(sp =>
{
return KeyEnvClient.Create(new KeyEnvOptions
{
Token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")!,
CacheTtl = TimeSpan.FromMinutes(5)
});
});
})
.Build();
// Load secrets at startup
using (var scope = host.Services.CreateScope())
{
var client = scope.ServiceProvider.GetRequiredService<KeyEnvClient>();
await client.LoadEnvAsync(
Environment.GetEnvironmentVariable("KEYENV_PROJECT")!,
"production"
);
}
host.Run();AWS Lambda with .NET
using Amazon.Lambda.Core;
using KeyEnv;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace MyLambda;
public class Function
{
private static readonly KeyEnvClient _client;
private static bool _secretsLoaded = false;
static Function()
{
_client = KeyEnvClient.Create(new KeyEnvOptions
{
Token = Environment.GetEnvironmentVariable("KEYENV_TOKEN")!,
CacheTtl = TimeSpan.FromMinutes(5)
});
}
public async Task<string> FunctionHandler(object input, ILambdaContext context)
{
// Load secrets once per cold start
if (!_secretsLoaded)
{
await _client.LoadEnvAsync(
Environment.GetEnvironmentVariable("KEYENV_PROJECT")!,
"production"
);
_secretsLoaded = true;
}
// Your handler logic here
var apiKey = Environment.GetEnvironmentVariable("API_KEY");
return $"Success with API key: {apiKey?.Substring(0, 10)}...";
}
}Background Service
using KeyEnv;
public class SecretsRefreshService : BackgroundService
{
private readonly KeyEnvClient _client;
private readonly ILogger<SecretsRefreshService> _logger;
public SecretsRefreshService(KeyEnvClient client, ILogger<SecretsRefreshService> logger)
{
_client = client;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
var count = await _client.LoadEnvAsync("project-id", "production", stoppingToken);
_logger.LogInformation("Refreshed {Count} secrets", count);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to refresh secrets");
}
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
}