BudgetExperiment supports multiple authentication modes. Choose the option that best fits your deployment:
| Mode | Use Case | Setup Time |
|---|---|---|
| None (auth off) | Demo, single-user, family | 0 min |
| Authentik (default) | Self-hosted identity, production | 15–30 min |
| Small teams with Google Workspace | 10 min | |
| Microsoft Entra ID | Enterprise / Azure AD | 15 min |
| Generic OIDC | Keycloak, Auth0, Okta, etc. | 10–20 min |
All authentication settings are configured via environment variables or appsettings.json. The two key variables are:
Authentication__Mode=OIDC # "None" or "OIDC"
Authentication__Provider=Authentik # "Authentik", "Google", "Microsoft", "OIDC"When Mode=None, no provider configuration is needed. When Mode=OIDC, configure the provider section that matches your Provider value.
The simplest option — no identity provider needed. All requests are treated as a single "Family" user.
Authentication__Mode=None- Evaluating BudgetExperiment locally
- Single-user or family use behind a private network
- Demo deployments
⚠️ Never expose an auth-off instance to the public internet. All data is accessible without credentials.
The application displays a banner and logs a warning at startup when authentication is disabled.
docker compose -f docker-compose.demo.yml up -dThis uses auth-off by default. See DEPLOY-QUICKSTART.md for details.
Authentik is the recommended identity provider for self-hosted production deployments.
- A running Authentik instance
- An OAuth2/OpenID Provider configured in Authentik
- In Authentik, go to Applications → Providers → Create.
- Choose OAuth2/OpenID Connect Provider.
- Configure:
- Name:
BudgetExperiment - Authorization flow: Select your authorization flow
- Client type:
Public - Redirect URIs:
https://your-budget-app.example.com/authentication/login-callback - Scopes:
openid,profile,email
- Name:
- Create an Application linked to this provider.
- Note the Application Slug (used in the authority URL) and Client ID.
Authentication__Mode=OIDC
Authentication__Provider=Authentik
Authentication__Authentik__Authority=https://your-authentik.example.com/application/o/budget-experiment/
Authentication__Authentik__Audience=budget-experiment
Authentication__Authentik__RequireHttpsMetadata=trueenvironment:
- Authentication__Mode=OIDC
- Authentication__Provider=Authentik
- Authentication__Authentik__Authority=${AUTHENTIK_AUTHORITY}
- Authentication__Authentik__Audience=${AUTHENTIK_AUDIENCE}
- Authentication__Authentik__RequireHttpsMetadata=${AUTHENTIK_REQUIRE_HTTPS:-true}Existing deployments that set Authentication__Authentik__Authority without explicitly setting Mode or Provider continue to work — Authentik is the default provider and OIDC is the default mode.
The legacy Authentication__Authentik__Enabled=false flag still disables authentication (treated as Mode=None), but a deprecation warning is logged. Migrate to Authentication__Mode=None when convenient.
Use your Google Workspace or personal Google account for authentication.
- A Google Cloud project with the OAuth consent screen configured
- OAuth 2.0 credentials (Web application type)
- Go to Google Cloud Console → APIs & Services → Credentials.
- Click Create Credentials → OAuth client ID.
- Select Web application.
- Configure:
- Name:
BudgetExperiment - Authorized JavaScript origins:
https://your-budget-app.example.com - Authorized redirect URIs:
https://your-budget-app.example.com/authentication/login-callback
- Name:
- Note the Client ID and Client Secret.
- Go to OAuth consent screen and add the following scopes:
openid,profile,email.
Authentication__Mode=OIDC
Authentication__Provider=Google
Authentication__Google__ClientId=123456789-xyz.apps.googleusercontent.com
Authentication__Google__ClientSecret=GOCSPX-xxxxxenvironment:
- Authentication__Mode=OIDC
- Authentication__Provider=Google
- Authentication__Google__ClientId=${GOOGLE_CLIENT_ID}
- Authentication__Google__ClientSecret=${GOOGLE_CLIENT_SECRET}- Google's OIDC authority (
https://accounts.google.com) is set automatically. - The
emailclaim is mapped topreferred_usernamefor consistency with other providers. - Google OAuth requires HTTPS for redirect URIs in production.
Integrate with your organization's Microsoft identity platform.
- An Azure account with permission to register applications
- Access to the Azure Portal
- Go to Azure Portal → Microsoft Entra ID → App registrations.
- Click New registration.
- Configure:
- Name:
BudgetExperiment - Supported account types:
- Single tenant — your organization only
- Multitenant — any Azure AD directory
- Redirect URI:
Single-page application→https://your-budget-app.example.com/authentication/login-callback
- Name:
- Note the Application (client) ID and Directory (tenant) ID.
Authentication__Mode=OIDC
Authentication__Provider=Microsoft
Authentication__Microsoft__ClientId=00000000-0000-0000-0000-000000000000
Authentication__Microsoft__TenantId=your-tenant-id| TenantId value | Who can sign in |
|---|---|
common (default) |
Any Microsoft account (personal + work/school) |
organizations |
Any Azure AD work/school account |
consumers |
Personal Microsoft accounts only |
| Specific GUID | Only accounts from that Azure AD tenant |
environment:
- Authentication__Mode=OIDC
- Authentication__Provider=Microsoft
- Authentication__Microsoft__ClientId=${MICROSOFT_CLIENT_ID}
- Authentication__Microsoft__TenantId=${MICROSOFT_TENANT_ID:-common}- Authority URL is computed automatically:
https://login.microsoftonline.com/{tenantId}/v2.0 - The
emailclaim is mapped topreferred_usernamefor consistency. - For confidential clients, you can also set
Authentication__Microsoft__ClientSecret.
Connect any OIDC-compliant identity provider.
Authentication__Mode=OIDC
Authentication__Provider=OIDC
Authentication__Oidc__Authority=https://your-idp.example.com/realms/master
Authentication__Oidc__ClientId=budget-experiment
Authentication__Oidc__ClientSecret=your-client-secret# Custom audience (if different from ClientId)
Authentication__Oidc__Audience=budget-api
# Disable HTTPS metadata requirement (dev only)
Authentication__Oidc__RequireHttpsMetadata=false
# Custom scopes (array binding)
Authentication__Oidc__Scopes__0=openid
Authentication__Oidc__Scopes__1=profile
Authentication__Oidc__Scopes__2=email
Authentication__Oidc__Scopes__3=custom-scope
# Custom claim mappings (source → target)
Authentication__Oidc__ClaimMappings__name=preferred_username
Authentication__Oidc__ClaimMappings__custom_role=roleAuthentication__Mode=OIDC
Authentication__Provider=OIDC
Authentication__Oidc__Authority=https://keycloak.example.com/realms/budget
Authentication__Oidc__ClientId=budget-experiment
Authentication__Oidc__ClientSecret=your-keycloak-secretAuthentication__Mode=OIDC
Authentication__Provider=OIDC
Authentication__Oidc__Authority=https://your-tenant.auth0.com/
Authentication__Oidc__ClientId=your-auth0-client-id
Authentication__Oidc__ClientSecret=your-auth0-client-secret
Authentication__Oidc__Audience=https://budget-api.example.comAuthentication__Mode=OIDC
Authentication__Provider=OIDC
Authentication__Oidc__Authority=https://your-org.okta.com/oauth2/default
Authentication__Oidc__ClientId=your-okta-client-id
Authentication__Oidc__ClientSecret=your-okta-client-secretenvironment:
- Authentication__Mode=OIDC
- Authentication__Provider=OIDC
- Authentication__Oidc__Authority=${OIDC_AUTHORITY}
- Authentication__Oidc__ClientId=${OIDC_CLIENT_ID}
- Authentication__Oidc__ClientSecret=${OIDC_CLIENT_SECRET}
- Authentication__Oidc__Audience=${OIDC_AUDIENCE:-}InvalidOperationException: Authentication is set to OIDC mode but no Authority is configured.
Cause: Mode=OIDC (the default) but no provider authority is set.
Solutions:
- If you want auth off: set
Authentication__Mode=None - If using Authentik: set
Authentication__Authentik__Authority=... - If using another provider: set the appropriate authority/clientId (see provider sections above)
Common causes:
- Wrong redirect URI — The redirect URI in your identity provider must exactly match
https://your-app/authentication/login-callback - HTTP vs HTTPS mismatch — Most providers require HTTPS redirect URIs. For local dev, set
RequireHttpsMetadata=false. - CORS issues — Ensure
AllowedHostsincludes your domain, or set it to*for testing.
In auth-off mode: This should not happen. Verify Authentication__Mode=None is set (case-insensitive).
In OIDC mode:
- Verify the token audience matches your configuration
- Check that scopes include
openid,profile,email - Verify the authority URL is reachable from the server
Some providers use different claim names. Use the Generic OIDC provider with custom claim mappings:
Authentication__Provider=OIDC
Authentication__Oidc__ClaimMappings__your_claim=preferred_usernameThe application needs a preferred_username or name claim for displaying the user's name, and sub for the user ID.
The "Running in demo mode" banner appears when Authentication__Mode=None. Set Authentication__Mode=OIDC and configure a provider to remove it.
- Set
Authentication__Mode=OIDCand configure your provider - Point
ConnectionStrings__AppDbto a production PostgreSQL instance - (Optional) Reassign demo data from the family user:
UPDATE "Transactions" SET "UserId" = 'your-real-user-guid' WHERE "UserId" = '00000000-0000-0000-0000-000000000001';
| Variable | Default | Description |
|---|---|---|
Authentication__Mode |
OIDC |
None or OIDC |
Authentication__Provider |
Authentik |
Authentik, Google, Microsoft, OIDC |
Authentication__Authentik__Authority |
— | Authentik OIDC provider URL |
Authentication__Authentik__Audience |
— | Authentik client/audience ID |
Authentication__Authentik__RequireHttpsMetadata |
true |
Require HTTPS for metadata endpoint |
Authentication__Google__ClientId |
— | Google OAuth client ID |
Authentication__Google__ClientSecret |
— | Google OAuth client secret |
Authentication__Microsoft__ClientId |
— | Microsoft Entra ID app client ID |
Authentication__Microsoft__TenantId |
common |
Azure AD tenant ID or alias |
Authentication__Microsoft__ClientSecret |
— | Microsoft client secret (optional) |
Authentication__Oidc__Authority |
— | Generic OIDC authority URL |
Authentication__Oidc__ClientId |
— | Generic OIDC client ID |
Authentication__Oidc__ClientSecret |
— | Generic OIDC client secret |
Authentication__Oidc__Audience |
— | Generic OIDC audience (if different from ClientId) |
Authentication__Oidc__RequireHttpsMetadata |
true |
Require HTTPS for metadata endpoint |
Authentication__Oidc__Scopes__N |
openid,profile,email |
Custom scopes (array) |
Authentication__Oidc__ClaimMappings__X |
— | Claim mappings (source=target) |