Hosting API
Exact .NET hosting signatures for registering, configuring, mapping, and consuming SqlOS.
| Item | Value |
|---|---|
| Package | SqlOS |
| Assembly | SqlOS.dll |
| Target framework | net9.0 |
Namespace: SqlOS
Assembly: SqlOS.dll
public abstract class SqlOSDbContext<TContext> : DbContext,
ISqlOSAuthServerDbContext,
ISqlOSFgaDbContext
where TContext : SqlOSDbContext<TContext>protected SqlOSDbContext(DbContextOptions<TContext> options)| Parameter | Type | Description |
|---|---|---|
options | DbContextOptions<TContext> | EF Core options registered for the derived application context. |
The base context registers SqlOS auth, email, calendar, and FGA entities in the EF model. Relational contexts also register the dbo.fn_IsResourceAccessible table-valued function. Its sealed OnModelCreating implementation invokes OnApplicationModelCreating for application-owned mappings.
SaveChanges and SaveChangesAsync synchronize tracked entities that implement ISqlOSResourceEntity into the FGA resource table before EF saves the unit of work.
protected virtual void OnApplicationModelCreating(ModelBuilder modelBuilder)Override this method instead of OnModelCreating:
using Microsoft.EntityFrameworkCore;
using SqlOS;
public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
: SqlOSDbContext<AppDbContext>(options)
{
public DbSet<Project> Projects => Set<Project>();
protected override void OnApplicationModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>(entity =>
{
entity.HasKey(project => project.Id);
entity.Property(project => project.Name).HasMaxLength(200).IsRequired();
});
}
}Namespace: SqlOS.Extensions
Type: WebApplicationBuilderExtensions
public static WebApplicationBuilder AddSqlOS<TContext>(
this WebApplicationBuilder builder,
Action<DbContextOptionsBuilder> configureDbContext,
Action<SqlOSOptions>? configureSqlOS = null)
where TContext : DbContext, ISqlOSAuthServerDbContext, ISqlOSFgaDbContext| Parameter | Type | Description |
|---|---|---|
builder | WebApplicationBuilder | The application host builder. |
configureDbContext | Action<DbContextOptionsBuilder> | Configures the application EF Core context. Use UseSqlServer(...) for the supported provider. |
configureSqlOS | Action<SqlOSOptions>? | Optional SqlOS configuration callback. |
Returns: the same WebApplicationBuilder, for chaining.
This overload calls AddDbContext<TContext> and registers the complete SqlOS service graph, hosted bootstrap, signing-key rotation, optional calendar synchronization, and dashboard middleware.
public static WebApplicationBuilder AddSqlOS<TContext>(
this WebApplicationBuilder builder,
Action<SqlOSOptions>? configure = null)
where TContext : DbContext, ISqlOSAuthServerDbContext, ISqlOSFgaDbContextUse this overload only when TContext is already registered in DI. It does not register the EF context.
AddSqlOS throws InvalidOperationException when option validation fails. Examples include an issuer path that does not match AuthServer.BasePath, PublicOrigin and issuer mismatch, password dashboard mode without a password, or incomplete email/phone provider configuration.
Namespace: SqlOS.Configuration
Type: SqlOSOptions
public SqlOSOptions UseSingleApplication(
string name,
Action<SqlOSSingleApplicationOptions>? configure = null)public SqlOSOptions UseSingleApplication(
IConfiguration configuration,
string sectionName = "SqlOS:Application")| Parameter | Type | Description |
|---|---|---|
name | string | Product/application display name. A client ID is derived from it unless explicitly configured. |
configure | Action<SqlOSSingleApplicationOptions>? | Describes the application: origin, Api/Mcp surfaces, hosted branding or headless UI, authorization model, and client overrides. |
configuration | IConfiguration | Configuration containing the single-application section. |
sectionName | string | Section path. Defaults to SqlOS:Application. |
Returns: the same SqlOSOptions instance.
Single-application mode creates one first-party public PKCE client and applies AuthPage/email branding defaults. It cannot be combined with explicit startup client seeds.
Namespace: SqlOS.AuthServer.Configuration
| Member | Type | Effect |
|---|---|---|
Name | string | Display name; also the default ClientName and AuthPage title. |
Origin | string? | Absolute HTTP(S) origin of the application (no path). Required when Api or Mcp is set. |
Api | string? | Absolute path of the REST resource, for example /api. Sets the SqlOS JWT scheme audience to {Origin}{Api}, the first-party client audience, and serves the RFC 9728 document at /.well-known/oauth-protected-resource. Lock routes with RequireAuthorization(). |
Mcp | string? | Absolute path of the MCP resource, for example /mcp. Registers scheme/policy SqlOS.Mcp with audience {Origin}{Mcp}, serves /.well-known/oauth-protected-resource{Mcp}, and enables client ID metadata documents plus resource indicators. The host maps Microsoft's MCP SDK and calls RequireAuthorization("SqlOS.Mcp"). |
Brand(Action<SqlOSAuthPageSeedOptions>) | method | Forwards to AuthServer.SeedAuthPage on top of the single-application defaults. |
Headless(string uiPath, Action<SqlOSHeadlessAuthOptions>? configure = null) | method | Uses your own sign-in UI at {Origin}{uiPath} instead of the hosted pages. Forwards to AuthServer.UseHeadlessAuthPage with a generated BuildUiUrl that passes request, view, error, email, displayName, pendingToken, mfaToken, consentToken, and ui_context. Requires Origin; uiPath must start with /. |
Headless(Action<SqlOSHeadlessAuthOptions>) | method | Forwards to AuthServer.UseHeadlessAuthPage unchanged; set BuildUiUrl yourself. |
Authorization(Action<SqlOSFgaSeedBuilder>) | method | Forwards to Fga.Seed. |
Audience, ClientId, RedirectPath, RedirectUris, AllowedScopes, AllowNativeHeadlessAuth | Client overrides. Audience defaults to {Origin}{Api} when Api is set. RedirectUris accepts any absolute URI without a fragment, including native custom-scheme callbacks. |
Declared surfaces are validated at startup: paths must be absolute, non-root, distinct and non-nested, and must not overlap /.well-known, the auth base path, or DashboardBasePath. Audience must equal {Origin}{Api} when both are set, and CIMD/resource indicators cannot be disabled after an Mcp surface is declared.
AddSqlOS registers those JWT schemes. Call RequireAuthorization() (or RequireAuthorization("SqlOS.Mcp") for a hand-mapped MCP route) on the endpoints you lock. A missing or wrong-audience token receives HTTP 401 with a Bearer challenge that names the scheme's realm and resource_metadata URL. The validated token is available through HttpContext.GetSqlOSValidatedToken() and HttpContext.User. Inspect Scope on that token in the handler when a client's granted ceiling must be checked. SqlOS does not wrap routes from a path string and does not handle CORS.
InvalidOperationException when name is empty.InvalidOperationException when the configuration section does not exist.InvalidOperationException when neither Origin nor an explicit redirect URI is supplied, the origin/redirect is invalid, a surface path violates the rules above, or explicit client seeds are also configured.public SqlOSOptions ConfigureApplication(string name, Action<SqlOSApplicationOptions> configure)Describes the host independently of client registration. SqlOSApplicationOptions contains the shared origin, API/MCP surfaces, branding, headless UI, scopes, credential presentation, and authorization seed methods shown above. SqlOSSingleApplicationOptions derives from it and adds ClientId, Audience, RedirectPath, and RedirectUris for the derived first-party client.
ConfigureApplication seeds no client. Use explicit client seeds, the administration API, or dashboard records. Declaring MCP still enables CIMD and resource indicators. The multiple-applications guide shows how to preserve an existing client's identity when graduating.
AddSqlOS registers an IStartupFilter that maps the AuthServer routes, audit-log admin routes, transactional-email admin routes, calendar routes (when SqlOSOptions.Calendar.Enabled is true), and the protected-resource documents for declared surfaces. They join the application's own route table, so the application's middleware (CORS, exception handling, rate limiting) runs in front of them and normal route precedence applies. The MCP transport is the host's AddMcpServer / MapMcp calls.
A leftover MapAuthServer() call is safe and idempotent: SqlOS withdraws its own copy of those routes and logs one warning. Remove the call.
Namespace: SqlOS.AuthServer.Extensions
Type: SqlOSAccessTokenValidationExtensions
public static SqlOSValidatedToken? GetSqlOSValidatedToken(
this HttpContext context)Returns: the validated token stored by the SqlOS authentication scheme; otherwise null.
Namespace: SqlOS.AuthServer.Authentication
Same-process extra audience. Same shape as AddJwtBearer: the scheme's ExpectedAudience is the required aud. Use it when one host exposes a second resource. A separate API host keeps AddJwtBearer against JWKS and accepts revoke-at-exp.
using SqlOS.AuthServer.Authentication;
builder.Services.AddAuthentication()
.AddSqlOSJwt("Billing", options => options.ExpectedAudience = $"{origin}/billing");
app.MapGroup("/billing").RequireAuthorization("Billing");using SqlOS.AuthServer.Extensions;
var api = app.MapGroup("/api").RequireAuthorization();
api.MapGet("/me", (HttpContext http) =>
{
var token = http.GetSqlOSValidatedToken();
return token?.UserId is { } userId
? Results.Ok(new { userId, token.OrganizationId, token.ClientId })
: Results.Unauthorized();
});using Microsoft.EntityFrameworkCore;
using ModelContextProtocol.AspNetCore;
using SqlOS.AuthServer.Authentication;
using SqlOS.AuthServer.Extensions;
using SqlOS.Extensions;
const string origin = "https://localhost:5001";
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException(
"Connection string 'DefaultConnection' was not configured.");
builder.AddSqlOS<AppDbContext>(
db => db.UseSqlServer(connectionString),
options =>
{
options.UseSingleApplication("Acme", app =>
{
app.Origin = origin;
app.Api = "/api";
app.Mcp = "/mcp";
app.Brand(page => page.PrimaryColor = "#0f172a");
app.Authorization(fga => fga
.ResourceType("project", "Project")
.Permission("PROJECT_READ", "Read projects", "project")
.Role("project_viewer", "Viewer").Can("PROJECT_READ"));
});
});
builder.Services.AddHttpContextAccessor();
builder.Services.AddMcpServer()
.WithHttpTransport(transport => transport.SessionMode = HttpServerSessionMode.Stateless)
.WithTools<AcmeTools>();
var app = builder.Build();
app.MapGet("/api/projects", (HttpContext http) =>
Results.Ok(new { user = http.GetSqlOSValidatedToken()!.UserId }))
.RequireAuthorization();
app.MapMcp("/mcp").RequireAuthorization(SqlOSJwtDefaults.McpPolicy);
app.Run();SqlOS does not map the MCP server. AuthServer.Issuer defaults to {Origin}/sqlos/auth.
SqlOS bootstraps its owned schema, signing key, default settings, client seed, and FGA core data when the host starts. Application EF migrations remain responsible only for application-owned tables.