SluiceBase is a self-hosted database query gateway. It gives a team controlled, auditable access to databases — secured by OIDC authentication, per-user permissions, and an optional approval workflow for write operations.
- OIDC authentication — integrates with any OIDC provider (Keycloak, Auth0, Entra ID, etc.)
- Permission model — assign read/write permissions per user and database
- Write approval workflow — write requests require approval before execution
- Query history — all queries are logged with results
- Schema browser — explore table schemas directly in the UI
- Customisable branding — app name, colour, logo, and favicon configurable at runtime
A single Docker container runs the .NET 10 API which also serves the React frontend. The only external dependencies at runtime are a PostgreSQL database (metadata store) and an OIDC provider.
Browser → SluiceBase (React SPA + .NET 10 API) → PostgreSQL (metadata)
→ Target databases
→ OIDC provider
- Docker
- PostgreSQL 16+ (metadata store)
- An OIDC provider with a confidential client configured (see OIDC setup)
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_USER: sluicebase
POSTGRES_PASSWORD: changeme
POSTGRES_DB: sluicebase
volumes:
- postgres-data:/var/lib/postgresql/data
app:
image: ghcr.io/yeongjonglim/sluice-base:latest
ports:
- "8080:8080"
environment:
ConnectionStrings__Metadata: "Host=postgres;Database=sluicebase;Username=sluicebase;Password=changeme"
Oidc__Authority: "https://your-keycloak/realms/your-realm"
Oidc__ClientId: "sluicebase"
Oidc__ClientSecret: "your-client-secret"
Permissions__Bootstrap__Admins__0: "admin@your-company.com"
depends_on:
- postgres
volumes:
postgres-data:docker run -p 8080:8080 \
-e ConnectionStrings__Metadata="Host=...;Database=sluicebase;Username=...;Password=..." \
-e Oidc__Authority="https://your-keycloak/realms/your-realm" \
-e Oidc__ClientId="sluicebase" \
-e Oidc__ClientSecret="your-client-secret" \
ghcr.io/yeongjonglim/sluice-base:latestThe app is available at http://localhost:8080.
HTTPS: deploy behind a reverse proxy (nginx, Caddy, Traefik) that terminates TLS. The container listens on HTTP only.
| Variable | Required | Default | Description |
|---|---|---|---|
ConnectionStrings__Metadata |
✓ | — | PostgreSQL connection string for the SluiceBase metadata database |
Oidc__Authority |
✓ | — | OIDC authority URL (e.g. https://keycloak/realms/myrealm) |
Oidc__ClientId |
✓ | — | OIDC client ID |
Oidc__ClientSecret |
✓ | — | OIDC client secret |
Migrations__AutoApply |
true |
Apply pending DB migrations on startup | |
Permissions__Bootstrap__Admins__0 |
— | Email of the first admin (granted full permissions on first login) | |
Branding__AppName |
SluiceBase |
Application name shown in the UI | |
Branding__PrimaryColor |
teal |
Mantine colour — see supported values | |
Branding__LogoUrl |
— | URL to a custom logo image — see using local files | |
Branding__FaviconUrl |
— | URL to a custom favicon — see using local files | |
Query__TimeoutSeconds |
30 |
Maximum query execution time in seconds | |
Mcp__Enabled |
true |
Enable the MCP server and its OAuth endpoints (see Connecting AI tools) | |
Mcp__ServerName |
sluicebase |
Client alias shown in connect snippets (letters, digits, -, _; falls back to sluicebase if invalid) |
|
Mcp__AccessTokenMinutes |
60 |
Lifetime of an MCP access token in minutes | |
Mcp__RefreshTokenDays |
30 |
Lifetime of an MCP refresh token in days | |
Mcp__AuthCodeSeconds |
120 |
Lifetime of an MCP OAuth authorization code in seconds |
Branding__PrimaryColor accepts any Mantine built-in colour name:
dark gray red pink grape violet indigo blue cyan teal green lime yellow orange
Mount a directory into /app/wwwroot/branding/ inside the container and set LogoUrl/FaviconUrl to the corresponding relative paths. The files are served natively as static assets.
# docker-compose.yml
services:
app:
image: ghcr.io/yeongjonglim/sluice-base:latest
volumes:
- ./branding:/app/wwwroot/branding:ro
environment:
- Branding__LogoUrl=/branding/logo.png
- Branding__FaviconUrl=/branding/favicon.icoPlace logo.png and favicon.ico in a local ./branding/ directory. Both LogoUrl and FaviconUrl also accept remote http(s):// URLs if the assets are hosted externally — in that case no volume mount is needed.
Migrations are applied automatically on startup by default. Set Migrations__AutoApply=false to disable this behaviour.
To apply migrations manually using the .NET CLI:
dotnet ef database update \
--project src/SluiceBase.Api \
--connection "Host=...;Database=sluicebase;Username=...;Password=..."Register a confidential OIDC client with these settings:
| Setting | Value |
|---|---|
| Client type | Confidential (authorization code + PKCE) |
| Redirect URI | https://your-domain/signin-oidc |
| Post-logout redirect URI | https://your-domain/signout-callback-oidc |
| Scopes | openid, profile, email |
The ID token must include the sub, email, and name claims.
Keycloak: create a realm, add a client with the settings above, and point Oidc__Authority to https://your-keycloak/realms/your-realm.
SluiceBase exposes a Model Context Protocol server so AI coding tools (Claude Code, Codex) can list databases, browse schema, and run read-only queries as the authenticated user — reusing the same per-database permissions, sensitive-column screening, and audit logging as the web UI.
The MCP endpoint is served at https://your-domain/mcp (streamable HTTP). Authentication uses OAuth 2.1: SluiceBase acts as the authorization server and brokers login to your existing OIDC provider, so users sign in with the same login page they already use — no extra credentials, and tokens are user-scoped and revocable.
Signed-in users can also open Connect AI tools (the ✨ icon in the app header) for copy-ready, per-client setup snippets pre-filled with this instance's URL and server name.
claude mcp add --transport http sluicebase https://your-domain/mcpThen in Claude Code, run /mcp, select sluicebase → Authenticate. A browser opens to your OIDC provider's login page; after signing in you're returned to the client and the tools become available.
Add a remote MCP server pointing at the same URL in your Codex MCP configuration:
[mcp_servers.sluicebase]
transport = "http"
url = "https://your-domain/mcp"Codex runs the same OAuth flow on first use.
| Tool | Description |
|---|---|
list_databases |
Lists the databases the user can query, grouped by server |
get_schema |
Returns a database's table/column schema (sensitive columns flagged) |
run_query |
Executes a read-only SQL query (subject to the user's query:execute permission, sensitive-column blocking, and audit logging — MCP-origin queries are tagged in the history) |
Set Mcp__Enabled=false to disable the MCP server and its OAuth endpoints entirely.
SluiceBase uses .NET Aspire to orchestrate all services locally, including Keycloak and PostgreSQL.
Prerequisites: .NET 10 SDK, Node.js 24, Docker
git clone https://github.com/yeongjonglim/sluice-base.git
cd sluice-base
dotnet run --project src/AppHostThe Aspire dashboard opens at https://localhost:15888. Once all services are healthy, use the Seed Server Registry command on the Metadata database resource to populate sample target databases.
The local stack runs behind a YARP gateway at https://localhost:5443 (Keycloak login, the SPA, and the API are all reached through it). Dev users are seeded in Keycloak: alice@example.com / dev (bootstrap admin) and bob@example.com / dev.
The MCP endpoint is served through the gateway at https://localhost:5443/mcp.
-
Trust the dev HTTPS certificate so an MCP client accepts the
localhostTLS connection:dotnet dev-certs https --trust
-
Start the stack (
dotnet run --project src/AppHost) and run the Seed Server Registry command from the dashboard. -
Sign in to
https://localhost:5443once asalice@example.com/devto bootstrap the admin user. Alice hasserver:manage, solist_databasesworks immediately. To exercise the permission path with a non-admin, sign in asbob@example.comand grant himquery:executeon a database via the Access admin page. -
Connect a client:
MCP Inspector (quickest way to drive the OAuth flow and call tools):
NODE_TLS_REJECT_UNAUTHORIZED=0 npx @modelcontextprotocol/inspector
Set Transport to Streamable HTTP, URL to
https://localhost:5443/mcp, and connect. (NODE_TLS_REJECT_UNAUTHORIZED=0is only needed to accept the local dev certificate.)Claude Code:
claude mcp add --transport http sluicebase https://localhost:5443/mcp
Then run
/mcp, select sluicebase → Authenticate, and sign in via the Keycloak page. -
Smoke-test the OAuth discovery without a client (no auth required):
curl -k https://localhost:5443/.well-known/oauth-protected-resource curl -k -i https://localhost:5443/mcp # expect 401 + WWW-Authenticate: Bearer resource_metadata=...
The OAuth + tool round-trip is also covered by the integration tests:
dotnet test tests/IntegrationTests --filter "McpTokenServiceTests|OAuthFlowTests|McpToolsTests"