Configure authentication
Either point your install at Dibbla's hosted auth, or run the Auth Service in your cluster.
The Dibbla platform has a single auth contract — a token signed by an Auth Service, validated against <auth-service-url>/api/v1/tokens/validate. Where that Auth Service runs is up to you.
Pick a path
| Aspect | Hosted (Dibbla) | Self-hosted |
|---|---|---|
| OAuth app registration | Dibbla’s | Yours (you create it in Google Cloud / Microsoft Entra) |
| Sign-in domain | app.dibbla.com | A host on your domain (e.g. app.example.com) |
| Org and user data | Stored at Dibbla | Stored in your cluster’s Postgres |
| In-cluster Postgres + Redis required for auth | No | Yes |
| JWT/signing keys | Managed by Dibbla | You generate and store them |
| Operational complexity | Lowest | Higher — you own the OAuth lifecycle and key rotation |
| Data residency | Dibbla holds identity data | All identity data in your cluster |
| Network dependency | Your cluster must reach app.dibbla.com to validate tokens | Self-contained |
Most teams start with hosted auth and only move to self-hosted when a compliance or air-gap requirement forces it.
Use Dibbla’s hosted auth
End state: users in your cluster sign in at app.dibbla.com with Dibbla’s app registration; tokens issued there are accepted by your platform services.
1. Create your org on Dibbla
Sign in at app.dibbla.com with the email you want as the owner. Create an org via the dashboard (or POST /api/v1/orgs with {"name": "Your Org"}). The org’s slug is what you’ll use everywhere below.
2. Mint a long-lived API token
In Settings → API tokens, create a token. This is what your platform services and your CLI will both use.
3. Point your Helm install at hosted auth
Override the platform services’ AUTH_SERVICE_URL so they validate tokens against app.dibbla.com instead of an in-cluster auth service:
api-gateway:
env:
AUTH_SERVICE_URL: https://app.dibbla.com
AUTH_LOGIN_URL: https://app.dibbla.com
deploy-api:
env:
AUTH_SERVICE_URL: https://app.dibbla.com
You can also drop the in-cluster auth-service workload, the bundled Postgres, and Redis since nothing inside your cluster needs them. The Helm chart doesn’t yet expose a clean auth-service.enabled: false toggle — until it does, you have two options:
- Leave the bundled services running and just ignore them. They consume resources but don’t interfere; the env-var overrides above are what matters.
- Apply a Kustomize overlay after
helm templatethat strips the auth-service Deployment, the bundledpostgresqlStatefulSet, and theredisworkloads.
A first-class global.auth.mode: hosted value (which would also disable the
unneeded subcharts) is planned. Until then, the env-var override above is the
supported path.
4. Configure the CLI
dibbla login --api-url https://your-platform.example.com --api-key dib_…
The CLI talks to your platform; your platform validates the token against Dibbla’s hosted auth.
The login adds a context named after your instance
rather than overwriting an existing login, so you can keep a Dibbla login and a
self-hosted one side by side and switch with dibbla context use. Pass
--context <name> to choose the name yourself.
5. How sign-in feels for your users
- User opens an app at
https://my-app.example.com. - The API Gateway redirects them to
https://app.dibbla.com(becauseAUTH_LOGIN_URLpoints there). - They sign in with Google or Microsoft using Dibbla’s app registration.
- They’re redirected back to
my-app.example.comwith a Dibbla-issued token. - Your API Gateway validates the token against
https://app.dibbla.com/api/v1/tokens/validateand lets them through.
Self-host the auth service
End state: a fully self-contained install. No outbound dependency on Dibbla; you own the OAuth client and the signing keys.
1. Register an OAuth client
In the Google Cloud Console, create an OAuth client ID of type Web application. Authorized redirect URI:
https://app.example.com/auth/google/callback
Replace app.example.com with whatever you set for auth-service.redirectBaseUrl. Capture the client ID and client secret.
(Microsoft Entra works similarly — see Microsoft Entra (Azure AD) below for the env var shape.)
2. Generate signing keys
openssl rand -hex 32 # JWT secret
openssl rand -hex 32 # Signing key
Rotating either value invalidates all existing tokens — every user signs out, every CI job needs a new API token. Set them once and store them in your secret manager.
3. Set Helm values
auth-service:
google:
clientId: <your-oauth-client-id>
clientSecret: <your-oauth-client-secret>
jwt:
secret: <your-jwt-secret>
signingKey: <your-signing-key>
redirectBaseUrl: https://app.example.com
allowedRedirectBaseUrls: https://app.example.com
allowedRedirectBaseUrls is comma-separated. Add additional UIs (the deploy UI on a different host, an internal console, etc.) here so the callback can return users to the correct origin.
4. Create the first organization and admin user
Once the platform is running, curl the admin endpoint:
curl -X POST https://api.example.com/api/v1/admin/orgs \
-H "Content-Type: application/json" \
-d '{
"name": "Your Org",
"domains": ["example.com"],
"admin_email": "[email protected]",
"admin_name": "Your Name"
}'
Fields:
name(required) — display name. The slug is derived from this.domains(optional) — email domains that auto-join this organization on first sign-in.admin_email,admin_name(optional) — when present, the admin is granted theownerrole on the new org. If a user with this email already exists, they’re added to the org instead of recreated.
The first user signs in via the OAuth flow at https://app.example.com — Google redirects to your callback URL, the Auth Service issues a session, and the user lands in the dashboard with owner permissions on the org you just created.
5. Configure the CLI
dibbla login --api-url https://api.example.com --api-key dib_…
This adds a context for your instance and leaves any other login intact.
Microsoft Entra (Azure AD)
Microsoft sign-in is a first-class chart value alongside Google. Add the auth-service.microsoft block to values.yaml:
auth-service:
google:
clientId: <your-google-client-id>
clientSecret: <your-google-client-secret>
microsoft:
clientId: <your-ms-client-id>
clientSecret: <your-ms-client-secret>
tenantId: <your-ms-tenant-id> # UUID, or "common" / "organizations" / "consumers"
Either provider alone, or both side-by-side. In the Microsoft Entra portal: App registrations → New registration → Web → Redirect URI https://app.<base-domain>/auth/microsoft/callback. Capture the Application (client) ID, generate a client secret under Certificates & secrets, and use either the Directory (tenant) ID or one of the special values (common for any account, organizations for any work/school account, consumers for personal MSAs only).
The chart wires MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET / MICROSOFT_TENANT_ID into the auth-service Deployment automatically.
What happens on subsequent sign-ins
- Users whose email domain matches an org’s
domainslist are auto-joined as a regular member on first sign-in. - Users without a matching domain need to be invited explicitly by an org owner.
- Every API call from
dibblacarries the user’s JWT (or an API token), and the API Gateway validates it against whichever Auth ServiceAUTH_SERVICE_URLpoints at.
Workload identity (workers & tool servers)
Apps deployed on your install that use the Go worker SDK authenticate to the workflow engine automatically — with no API token. The platform mints a workload identity for every deployment: a projected, auto-rotating Kubernetes ServiceAccount token that the SDK (v0.0.18+) picks up and presents on connect. The Auth Service validates it against your cluster’s TokenReview API and resolves which organization and deployment is calling. There is nothing for your users to provision, rotate, or leak — and an expired-token outage is structurally impossible.
Requirements (all defaults — listed for completeness):
- Chart ≥ 0.5.0 with
auth-service.rbac.create: true(the default). This grants the Auth Service the two permissions it needs:tokenreviews createandserviceaccounts get. - The token audience must agree between the two services. Both default to
dibbla-control-plane; override withdeploy-apienvDIBBLA_WORKLOAD_AUDIENCEandauth-serviceenvWORKLOAD_AUDIENCE— always together. - To disable the feature entirely: set
WORKLOAD_IDENTITY_ENABLED=falseon the Auth Service andDIBBLA_WORKLOAD_AUDIENCE=""on Deploy API. Workers then need a personal API token (ak_…) as before.
helm upgrade --reuse-values does not pick up new chart defaults. When
upgrading from a chart older than 0.5.0, pass --set auth-service.rbac.create=true explicitly once, or workload tokens will be
rejected with Invalid or expired API token while everything else looks
healthy.
Local development is unchanged: a worker running outside the cluster sets SERVER_API_TOKEN to a personal API token from the console, which always takes precedence.
The Auth Service as an OAuth authorization server (platform connector)
When the platform connector is on, your self-hosted Auth Service is also an OAuth 2.1 authorization server: AI agents connect to mcp.<base-domain>/platform by discovering it, running an authorization-code flow with PKCE through your normal Google/Microsoft sign-in, and consenting to scopes. This only applies to the self-hosted auth path — hosted auth at app.dibbla.com issues no tokens for your MCP endpoint.
What changes for your OAuth registration
Nothing. The Google/Microsoft client you registered above is still the only upstream identity provider; the connector adds a second, downstream role in which the Auth Service issues tokens to agents. The redirect URI you registered at Google/Microsoft stays https://app.<base-domain>/auth/google/callback. The Auth Service’s own login step returns the user to https://auth.<base-domain>/oauth/authorize afterwards, and the chart adds that origin to allowedRedirectBaseUrls for you while the connector is on.
Issuer host
The issuer is https://auth.<base-domain> — a hostname of its own, because RFC 8414 discovery (/.well-known/oauth-authorization-server) must live at the issuer’s root. The chart routes it straight from the ingress controller to the Auth Service’s API port; only the public endpoints (/.well-known/*, /oauth/*, the consent page and the login handoff) are meaningful there. Everything that needs a signed-in session still goes through api.<base-domain>.
Secrets
Two values, both in values.yaml:
auth-service.jwt.secret— already required; the MCP server needs the same value asmcp-server.platform.jwtSecretto verify the tokens the Auth Service signs.global.platformConnector.actorAssertionSecret— a second secret, different from the JWT secret. The MCP server never forwards an agent’s token downstream; it presents a short-lived assertion signed with this key instead, and the Auth Service verifies it. Rotate it for both services in the samehelm upgrade.
The connector reuses the JWT secret, so the note above applies unchanged: rotating it invalidates every session, API token and agent grant on the platform. Rotate the actor-assertion secret freely; rotate the JWT secret only when you mean to.
Registering agent clients
Three ways a client can exist, chosen by how much you trust it:
| Client | How it registers | Lifetime |
|---|---|---|
| Pre-registered | You insert it into auth_db.platform_oauth_clients — by design there is no API for this; the reference is the seed script in app-hosting-service/auth-service/scripts/e2e/ | never expires |
| Client ID Metadata Document | The client’s client_id is an https URL to its metadata document. Nothing is registered and no client row is created: the document is fetched and validated on every authorization | no record |
| Dynamic registration (RFC 7591) | POST /oauth/register, bounded to 100 active clients and 5 per origin | 30 days |
Redirect URIs are matched exactly — no prefixes, no wildcards — and only 127.0.0.1, [::1] and localhost loopbacks may be http. A metadata-document client that changes its document is still the same client — the URL is the identity — but the change is shown to the user: an existing approval covers only the exact document it was granted against, so a changed document brings the approval page back instead of signing the user straight in. To revoke a client, set its row is_active = false and revoke its rows in platform_access_grants; the MCP server checks grant liveness on every call, so a revoked grant is refused on the next request even while its token is still within its lifetime. A metadata-document client has no row to deactivate until you write one: insert a row for its client_id URL with is_active = false, which is how such a client is blocked. A user can disconnect an agent themselves from their account, which revokes the grant and its refresh-token family. Operating detail — rotation, emergency disable, log queries — is in the chart’s RUNBOOK.md § Platform connector.