Configuration Guide
Complete reference for configuring Beacon — connection strings, the required encryption key, authentication, AI/LLM, email, scheduling, and the metadata database.
This guide applies to both delivery modes: running the Beacon.SampleProject host and embedding the Beacon.* NuGet packages in your own ASP.NET Core app. Configuration is identical either way.
Configuration in Program.cs
Beacon is wired in Program.cs. The canonical setup (from Beacon.SampleProject) is:
using Beacon.AI;
using Beacon.Api;
using Beacon.Core;
using Beacon.Core.PostgreSql;
using Beacon.MCP;
using Beacon.UI;
// Host identity + SignalR plumbing
builder.Services.AddBeaconHostInfrastructure();
// Core services, scheduler, connectors, metadata provider
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>(); // your IBeaconScheduler implementation
options.BaseUrl = "https://localhost:7187";
options.UseAI = true;
options.AddEmailAdapter<BeaconMailSender>();
options.Authorization.Enabled = true;
options.Authentication.EnableLoginForm = true;
options.AddAuthenticationProvider<DatabaseAuthenticationProvider>();
options.UserManagement = new UserManagementOptions { Enabled = true };
})
.AddPostgreSqlConnector()
.AddSqlServerConnector()
.AddMySqlConnector()
// ... other connectors ...
.UsePostgreSql(builder.Configuration.GetConnectionString("BeaconContext")!, "beacon");
builder.Services.AddBeaconCookieAuthentication("/");
builder.Services.AddBeaconOidcAuthentication(builder.Configuration); // optional SSO
builder.Services.AddBeaconAI(builder.Configuration);
builder.Services.AddBeaconMcp();
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseStaticFiles();
app.UseMiddleware<ApiKeyAuthMiddleware>();
app.UseAuthentication();
app.UseMiddleware<BeaconCookieAuthMiddleware>();
app.UseAuthorization();
app.UseAntiforgery();
app.MapOpenApi(); // /openapi/v1.json
app.MapBeaconApi(); // /beacon/api/*
app.MapLoginEndpoints("/beacon", beaconConfiguration);
app.MapHub<BeaconHub>("/beacon/api/hub").RequireAuthorization();
app.MapMcp("/beacon/mcp").RequireAuthorization();
app.MapBeaconUi(); // React SPA at root /
The React SPA is served at the root URL
/by theBeacon.UIRazor Class Library (it builds fromBeacon.UI/webintoBeacon.UI/wwwroot). The REST API lives under/beacon/api/*, the MCP server at/beacon/mcp, the SignalR hub at/beacon/api/hub, and the OpenAPI document at/openapi/v1.json.
Base URL Configuration
BaseUrl is the public origin where Beacon is hosted. It’s used to build clickable links in notifications (e.g. Teams cards) back to the details page in the app.
options.BaseUrl = "https://localhost:7187"; // development
options.BaseUrl = "https://staging.example.com"; // staging
options.BaseUrl = "https://beacon.example.com"; // production
options.BaseUrl = builder.Configuration["Beacon:BaseUrl"]; // from config
appsettings.json
{
"Beacon": {
"BaseUrl": "https://beacon.example.com",
"EncryptionKey": "your-secure-32-byte-base64-key"
}
}
The SPA is served at the root
/, so notification links resolve to paths like{BaseUrl}/notifications/{id}— no/beaconUI prefix.
Encryption Key Configuration ⚠️ REQUIRED
Beacon:EncryptionKey is required. It encrypts sensitive data — most importantly data-source connection strings — at rest using AES-256.
Generate a Secure Key
openssl rand -base64 32
This produces a 32-byte key (base64-encoded) suitable for AES-256.
Configuration
{
"Beacon": {
"EncryptionKey": "k8J3m9Lp2Nq5Rt8Vw1Yz4Bc7Df0Gh3Jk6Lm9No2Pq="
}
}
Security Best Practices
⚠️ Never commit the encryption key to source control.
Development — User Secrets:
dotnet user-secrets set "Beacon:EncryptionKey" "$(openssl rand -base64 32)"
Production — environment variable:
export BEACON_ENCRYPTION_KEY="your-production-key-here"
{
"Beacon": {
"EncryptionKey": "${BEACON_ENCRYPTION_KEY}"
}
}
Production — Azure Key Vault:
var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable("VaultUri"));
var secretClient = new SecretClient(keyVaultEndpoint, new DefaultAzureCredential());
var secret = await secretClient.GetSecretAsync("BeaconEncryptionKey");
builder.Configuration["Beacon:EncryptionKey"] = secret.Value.Value;
What Gets Encrypted
- Data-source connection strings (stored in the metadata database)
- Other sensitive configuration values as needed
API keys are not encrypted — they are SHA256-hashed, and the raw key is shown to the user once at creation.
Error if Missing
If the encryption key is not configured, Beacon throws on startup:
InvalidOperationException: Beacon:EncryptionKey must be configured.
Generate a secure key with: openssl rand -base64 32
Authentication
Beacon authentication is cookie-based. The Beacon.Auth cookie is HttpOnly with SameSite=Lax. Identity is resolved through a pluggable IBeaconAuthenticationProvider. There is no basic auth and no default admin/admin account — the first-run setup flow creates the initial admin user.
Login Form (cookie auth)
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>();
options.Authentication.EnableLoginForm = true;
options.AddAuthenticationProvider<DatabaseAuthenticationProvider>();
})
.UsePostgreSql(connectionString, "beacon");
// Login redirect target — the SPA serves the login form at /login
builder.Services.AddBeaconCookieAuthentication("/");
app.MapLoginEndpoints("/beacon", beaconConfiguration);
Authentication Providers
| Provider | Use Case |
|---|---|
DatabaseAuthenticationProvider |
Internal users with passwords stored in Beacon |
JwtExternalApiAuthenticationProvider |
External JWT / OAuth identity provider |
HybridAuthenticationProvider |
Both internal and external users |
Optional: OIDC / SSO
builder.Services.AddBeaconOidcAuthentication(builder.Configuration);
{
"Beacon": {
"Authentication": {
"Oidc": {
"Enabled": true,
"Authority": "https://login.microsoftonline.com/{YOUR_TENANT_ID}/v2.0",
"ClientId": "{YOUR_CLIENT_ID}",
"ClientSecret": "${OIDC_CLIENT_SECRET}",
"CallbackPath": "/signin-oidc",
"Scopes": ["openid", "profile", "email"],
"DefaultRoleName": "Viewer",
"DisplayName": "Microsoft",
"McpJwksEndpoint": "https://login.microsoftonline.com/{YOUR_TENANT_ID}/discovery/v2.0/keys"
}
}
}
}
DefaultRoleName is the role assigned to first-time SSO users; DisplayName labels the SSO button on the login page.
API Keys
Beacon issues API keys for programmatic and MCP access — see the API Keys Guide:
- SHA256-hashed at rest; the raw key is shown once at creation
- Carry scopes:
Read,Execute,Admin - Support optional project restrictions
- Authenticated by
ApiKeyAuthMiddleware, which runs beforeUseAuthentication
JWT Bearer for MCP Clients
MCP clients can also authenticate with JWT bearer tokens issued by your OIDC provider. When OIDC is enabled, set McpJwksEndpoint to the provider’s JWKS (signing keys) URL — Beacon validates the token’s signature, issuer, and audience against it. This lets AI assistants use the same identity provider as your users, without cookies or long-lived API keys.
For complete user-management and provider documentation (external JWT setup, custom providers, roles), see the User Management Guide.
Authorization
Authorization is controlled via options and a pluggable provider.
options.Authorization.Enabled = true;
options.AddAuthorizationProvider<MyCustomProvider>();
Custom Authorization Provider
public class MyAuthorizationProvider : IBeaconAuthorizationProvider
{
private readonly IBeaconUserContext _userContext;
public MyAuthorizationProvider(IBeaconUserContext userContext)
{
_userContext = userContext;
}
public Task<bool> HasReadPermissionAsync(CancellationToken cancellationToken = default)
=> Task.FromResult(_userContext.IsAuthenticated);
public Task<bool> HasWritePermissionAsync(CancellationToken cancellationToken = default)
=> Task.FromResult(_userContext.HasClaim(BeaconClaims.Role, "Admin"));
// Implement other methods...
}
// Register it
options.AddAuthorizationProvider<MyAuthorizationProvider>();
For complete authorization documentation, see the Authorization Guide.
User Management
options.Authorization.Enabled = true;
options.Authentication.EnableLoginForm = true;
options.AddAuthenticationProvider<DatabaseAuthenticationProvider>();
options.UserManagement = new UserManagementOptions
{
Enabled = true,
AllowInternalUsers = true,
MinimumPasswordLength = 8,
RequirePasswordComplexity = true
};
| Option | Description | Default |
|---|---|---|
Enabled |
Enable user-management features | false |
AllowInternalUsers |
Allow password-based users | true |
MinimumPasswordLength |
Minimum password length | 8 |
RequirePasswordComplexity |
Require mixed case, numbers, symbols | true |
AI / LLM Configuration (Optional — Experimental)
Experimental Feature: AI-powered features (auto-documentation, natural-language → query, anomaly detection) are experimental and may produce incorrect results. Configure only if you’ll validate AI-generated content.
The LLM provider is runtime-swappable — it can be changed at runtime via Admin Settings without a restart. All LLM calls go through a request queue that enforces concurrency limits. Do not hard-code provider assumptions; read capabilities through the abstraction.
LLM settings in
appsettings.jsonact as startup defaults. Values configured in Admin Settings take precedence and support hot-swapping providers.
Supported Providers
The Provider value is one of: OpenAI, Claude (Anthropic), AzureOpenAI, Bedrock (AWS).
Basic Configuration
{
"Beacon": {
"LLM": {
"Provider": "OpenAI",
"ApiKey": "sk-your-api-key-here",
"Model": "gpt-4o"
}
}
}
Complete Configuration
{
"Beacon": {
"LLM": {
"Provider": "OpenAI",
"ApiKey": "sk-your-api-key-here",
"Model": "gpt-4o",
"FastModel": "gpt-4o-mini",
"Limits": {
"MaxConcurrentRequests": 50,
"TokensPerMinute": 80000,
"RequestsPerMinute": 1000,
"MonthlyBudget": 100.00
}
}
}
}
FastModel is optional: Beacon routes simple, high-volume operations (classification, short summaries) to the fast model and reserves the main Model for complex generation. If omitted, sensible per-provider defaults are used (gpt-4o-mini for OpenAI, claude-haiku-4-20250514 for Claude).
Anthropic Claude
{
"Beacon": {
"LLM": {
"Provider": "Claude",
"ApiKey": "sk-ant-...",
"Model": "claude-sonnet-4-20250514"
}
}
}
Azure OpenAI
Azure requires the Endpoint of your resource; Model is your deployment name.
{
"Beacon": {
"LLM": {
"Provider": "AzureOpenAI",
"ApiKey": "your-azure-key",
"Model": "your-deployment-name",
"Endpoint": "https://your-resource.openai.azure.com"
}
}
}
AWS Bedrock
Bedrock requires a Region. Credentials come either from the default AWS chain (IAM role, environment variables) — leave ApiKey empty — or explicitly as "accessKey:secretKey" (plus an optional SessionToken for temporary credentials).
{
"Beacon": {
"LLM": {
"Provider": "Bedrock",
"ApiKey": "",
"Region": "eu-west-1",
"Model": "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
}
}
}
Rate Limiting
The request queue caps concurrency and throughput:
| Setting | Description |
|---|---|
MaxConcurrentRequests |
Max parallel AI requests |
TokensPerMinute |
Token throughput cap |
RequestsPerMinute |
Request rate cap — match your provider tier |
MonthlyBudget |
Monthly spend cap (USD) tracked by the usage service |
Production — Use Environment Variables
{
"Beacon": {
"LLM": {
"ApiKey": "${LLM_API_KEY}"
}
}
}
Metadata Database Provider
Beacon’s metadata database runs on EF Core 9 with dual-provider support (PostgreSQL and SQL Server). The default schema is beacon (configurable). Dapper is used for hot paths.
PostgreSQL
using Beacon.Core;
using Beacon.Core.PostgreSql;
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>();
})
.UsePostgreSql(
builder.Configuration.GetConnectionString("BeaconContext")!,
"beacon"); // optional schema, defaults to "beacon"
{
"ConnectionStrings": {
"BeaconContext": "Host=localhost;Database=beacon;Username=postgres;Password=yourpassword"
}
}
SQL Server
using Beacon.Core;
using Beacon.Core.SqlServer;
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>();
})
.UseSqlServer(
builder.Configuration.GetConnectionString("BeaconContext")!,
"beacon");
{
"ConnectionStrings": {
"BeaconContext": "Server=localhost;Database=beacon;User Id=sa;Password=YourPassword123!;TrustServerCertificate=True"
}
}
Data-Source Connectors
Register a connector for each kind of data source you intend to monitor. Beacon ships nine connectors:
builder.Services.AddBeaconServices(builder.Configuration, options => { /* ... */ })
.AddPostgreSqlConnector()
.AddSqlServerConnector()
.AddMySqlConnector()
.AddBigQueryConnector()
.AddSnowflakeConnector()
.AddDatabricksConnector()
.AddAzureSynapseConnector()
.AddCloudWatchConnector()
.AddApiConnector()
.UsePostgreSql(connectionString, "beacon");
| Connector | Package |
|---|---|
| PostgreSQL | Beacon.Connector.PostgreSql |
| SQL Server | Beacon.Connector.SqlServer |
| MySQL | Beacon.Connector.MySql |
| Google BigQuery | Beacon.Connector.BigQuery |
| Snowflake | Beacon.Connector.Snowflake |
| Databricks | Beacon.Connector.Databricks |
| Azure Synapse | Beacon.Connector.AzureSynapse |
| AWS CloudWatch | Beacon.Connector.CloudWatch |
| Generic REST API | Beacon.Connector.Api |
Individual data-source connection strings are entered in the UI and encrypted at rest with your Beacon:EncryptionKey. See the Data Sources Guide.
Connection String Reference
PostgreSQL
Host=hostname;Port=5432;Database=dbname;Username=user;Password=pass
Host=hostname;Database=dbname;Username=user;Password=pass;SSL Mode=Require
Host=hostname;Database=dbname;Username=user;Password=pass;Pooling=true;MinPoolSize=0;MaxPoolSize=100
SQL Server
Server=hostname;Database=dbname;User Id=user;Password=pass;TrustServerCertificate=True
Server=hostname;Database=dbname;Integrated Security=True
Server=hostname;Database=dbname;User Id=user;Password=pass;Encrypt=True;TrustServerCertificate=False
MySQL
Server=hostname;Port=3306;Database=dbname;Uid=user;Pwd=pass
Server=hostname;Database=dbname;Uid=user;Pwd=pass;SslMode=Required
Scheduling
Beacon does not bundle a job runner. All recurring work goes through the IBeaconScheduler abstraction — you plug in the scheduler your host already uses:
namespace Beacon.Core.Worker;
public interface IBeaconScheduler
{
void AddOrUpdate(int subscriptionId, string subscriptionName, string cron);
void Remove(int subscriptionId, string subscriptionName);
// optional — data-quality contract evaluation schedules
void AddOrUpdateDataQualityJob(int contractId, string contractName, string cron);
void RemoveDataQualityJob(int contractId, string contractName);
// optional — fire-and-forget background work used by the AI features;
// returns the job id (used to correlate JobStatusChanged push events)
string EnqueueProjectDocumentation(int projectId, int userId, string? notifyUserId);
string EnqueueAiActorThinkCycle(int actorId, int subscriptionId);
}
The optional members have default implementations that throw, so hosts that don’t use data-quality contracts or AI features only implement the two subscription methods.
Beacon calls AddOrUpdate whenever a subscription is created or its cron changes, and Remove when it’s deleted or disabled. Your implementation maps those calls onto recurring jobs that invoke IJobService.ExecuteQuery(subscriptionId) on the cron schedule.
Scheduler Implementation
using Beacon.Core.Worker;
public class BeaconScheduler : IBeaconScheduler
{
public void AddOrUpdate(int subscriptionId, string subscriptionName, string cron)
{
// register/update a recurring job in your job runner that calls
// IJobService.ExecuteQuery(subscriptionId) on the given cron schedule
}
public void Remove(int subscriptionId, string subscriptionName)
{
// remove the recurring job
}
}
// Register it
options.AddBeaconScheduler<BeaconScheduler>();
Any job runner with recurring/cron support works. We recommend Moberg Warp — define an IJob that calls IJobService.ExecuteQuery and map AddOrUpdate/Remove onto Warp’s AddOrUpdateRecurringJob/remove APIs; you get retries, concurrency guards, and a job dashboard out of the box. Quartz.NET is another valid choice. Beacon.SampleProject ships a complete working reference implementation you can copy as a starting point.
Email Adapter
Beacon does not ship a default email implementation. Provide your own IEmailAdapter and register it via options.AddEmailAdapter<...>().
using Beacon.Core.Adapters.Mail;
using System.Net;
using System.Net.Mail;
public class SmtpEmailAdapter : IEmailAdapter
{
private readonly IConfiguration _configuration;
public SmtpEmailAdapter(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task SendEmailAsync(string to, string subject, string body, Stream? attachment = null)
{
using var smtpClient = new SmtpClient
{
Host = _configuration["Email:SmtpHost"],
Port = int.Parse(_configuration["Email:SmtpPort"]),
EnableSsl = true,
Credentials = new NetworkCredential(
_configuration["Email:Username"],
_configuration["Email:Password"])
};
var message = new MailMessage
{
From = new MailAddress(
_configuration["Email:FromAddress"],
_configuration["Email:FromName"]),
Subject = subject,
Body = body,
IsBodyHtml = true
};
message.To.Add(to);
if (attachment != null)
{
message.Attachments.Add(new Attachment(attachment, "results.csv", "text/csv"));
}
await smtpClient.SendMailAsync(message);
}
}
Register it:
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>();
options.AddEmailAdapter<SmtpEmailAdapter>();
})
.UsePostgreSql(connectionString, "beacon");
{
"Email": {
"SmtpHost": "smtp.gmail.com",
"SmtpPort": "587",
"Username": "alerts@yourdomain.com",
"Password": "your-app-password",
"FromAddress": "alerts@yourdomain.com",
"FromName": "Beacon Alerts"
}
}
Teams and Jira notifications work out of the box — configure them per recipient in the UI. See the Notifications Guide.
Schema Configuration
The default schema is beacon. Override it for multi-tenancy or environment separation:
var schema = builder.Configuration["Beacon:Schema"] ?? "beacon";
builder.Services.AddBeaconServices(builder.Configuration, options =>
{
options.AddBeaconScheduler<BeaconScheduler>();
})
.UsePostgreSql(
builder.Configuration.GetConnectionString("BeaconContext")!,
schema);
{
"Beacon": {
"Schema": "production_beacon"
}
}
Metadata Loading (Large Databases)
Beacon introspects the schemas of your monitored data sources to power the database explorer, documentation, and MCP context. For very large databases you can bound that work:
{
"Beacon": {
"MetadataLoading": {
"Enabled": true,
"MaxTables": 500,
"MaxColumnsPerTable": 200,
"LoadTableNamesOnly": false,
"IncludeSchemas": ["public", "app"],
"ExcludeSchemas": ["information_schema", "pg_catalog"]
}
}
}
| Setting | Description |
|---|---|
Enabled |
Set false to disable metadata loading entirely |
MaxTables |
Cap on tables loaded per data source (0 = unlimited) |
MaxColumnsPerTable |
Cap on columns loaded per table (0 = unlimited) |
LoadTableNamesOnly |
Load only table names, skipping columns |
IncludeSchemas |
Whitelist — only load these schemas |
ExcludeSchemas |
Blacklist — skip these schemas |
Security
Database User Permissions
Beacon metadata database (PostgreSQL):
CREATE USER beacon WITH PASSWORD 'strong-password';
GRANT ALL PRIVILEGES ON DATABASE beacon TO beacon;
GRANT ALL ON SCHEMA beacon TO beacon;
Monitored data sources (read-only recommended):
CREATE USER beacon_readonly WITH PASSWORD 'strong-password';
GRANT CONNECT ON DATABASE your_database TO beacon_readonly;
GRANT USAGE ON SCHEMA public TO beacon_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO beacon_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO beacon_readonly;
Connection String Security
- ✅ Use User Secrets for development
- ✅ Use Azure Key Vault or similar for production
- ✅ Use read-only users for monitored data sources
- ✅ Enable SSL/TLS in production
- ✅ Rotate passwords regularly
User Secrets (development):
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:BeaconContext" "Host=localhost;Database=beacon;Username=postgres;Password=devpassword"
Azure Key Vault (production):
builder.Configuration.AddAzureKeyVault(
new Uri($"https://{keyVaultName}.vault.azure.net/"),
new DefaultAzureCredential());
Reverse Proxy / Forwarded Headers
When Beacon runs behind a reverse proxy (nginx, Traefik, a cloud load balancer), enable forwarded-headers processing so rate limiting and redirects see the real client IP and scheme. It is off by default and trusts only the proxies you whitelist:
{
"Beacon": {
"ForwardedHeaders": {
"Enabled": true,
"KnownProxies": ["10.0.0.5"]
}
}
}
Only enable this when a trusted proxy actually sits in front of Beacon, and always whitelist its address. Blindly trusting
X-Forwarded-Forlets clients spoof their IP past the login rate limiter.
Logging
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Beacon": "Debug",
"Microsoft.AspNetCore": "Warning"
}
}
}
No PII in logs. User-supplied query text, connection strings, full row payloads, and auth tokens are never logged — Beacon logs identifiers and counts only.
Complete appsettings.json Example
{
"ConnectionStrings": {
"BeaconContext": "Host=localhost;Database=beacon;Username=beacon;Password=secretpass;Pooling=true;MaxPoolSize=50"
},
"Beacon": {
"EncryptionKey": "your-secure-32-byte-base64-key",
"Schema": "beacon",
"BaseUrl": "https://beacon.example.com",
"ForwardedHeaders": {
"Enabled": false,
"KnownProxies": []
},
"LLM": {
"Provider": "OpenAI",
"ApiKey": "${LLM_API_KEY}",
"Model": "gpt-4o",
"FastModel": "gpt-4o-mini"
}
},
"Email": {
"SmtpHost": "smtp.gmail.com",
"SmtpPort": "587",
"Username": "alerts@yourdomain.com",
"Password": "app-specific-password",
"FromAddress": "alerts@yourdomain.com",
"FromName": "Beacon Alerts"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Beacon": "Information"
}
}
}
LLM settings in
appsettings.jsonare optional startup defaults. Once configured via Admin Settings, database values take precedence.
Next Steps
Explore Data Sources, Queries, Subscriptions, and more
Create your first alert end to end
Integrate Beacon with AI agents over MCP