Sample Config
version: 1
# logging configuration
log:
# debug, info, warning, error, fatal - default 'info'
level: debug
# none(default), stdout, db
audit_events: none
# list of audit events to be ignored
# e.g. ["app.user.created", "app.permission.checked"]
ignored_audit_events: []
app:
port: 8000
grpc:
port: 8001
# optional tls config
# tls_cert_file: "temp/server-cert.pem"
# tls_key_file: "temp/server-key.pem"
# tls_client_ca_file: "temp/ca-cert.pem"
# port for application metrics
metrics_port: 9000
# enable pprof endpoints for cpu/mem/mutex profiling
profiler: false
# WARNING: identity_proxy_header bypass all authorization checks and shouldn't be used in production
identity_proxy_header: X-Frontier-Email
# cross-origin resource sharing configuration
cors:
# allowed_origins is origin value from where we want to allow cors
allowed_origins:
- "https://example.com" # use "*" to allow all origins
allowed_methods:
- POST
- GET
- PUT
- PATCH
- DELETE
allowed_headers:
- Authorization
exposed_headers:
- Content-Type
# configuration to allow authentication in frontier
authentication:
# to use frontier as session store
session:
# both of them should be 32 chars long
# hash helps identify if the value is tempered with
hash_secret_key: "hash-secret-should-be-32-chars--"
# block helps in encryption
block_secret_key: "block-secret-should-be-32-chars-"
# domain used for setting cookies, if not set defaults to request origin host
domain: ""
# same site policy for cookies
# can be one of: "", "lax"(default value), "strict", "none"
same_site: "lax"
# secure flag for cookies
secure: false
# validity of the session
validity: "720h"
# Learn more about session management: ../authn/session.md
# once authenticated, server responds with a jwt with user context
# this jwt works as a bearer access token for all APIs
token:
# generate key file via "./frontier server keygen"
# if not specified, access tokens will be disabled
# example: /opt/rsa
rsa_path: ""
# if rsa_path is not specified, rsa_base64 can be used to provide the rsa key in base64 encoded format
rsa_base64: ""
# issuer claim to be added to the jwt
iss: "http://localhost.frontier"
# validity of the token
validity: "1h"
# custom claims configuration for the jwt
claims:
# if set to true, the jwt will contain the org ids of the user in the claim
add_org_ids: true
# if set to true, the jwt will contain the user email in the claim
add_user_email: true
# Public facing host used for oidc redirect uri and mail link redirection
# after user credentials are verified.
# If frontier is exposed behind a proxy, this should set as proxy endpoint
# e.g. http://localhost:7400/v1beta1/auth/callback
# Only the first host is used for callback by default, if multiple hosts are provided
# they can be used to override the callback host for specific strategies using query param
callback_urls: ["http://localhost:8000/v1beta1/auth/callback"]
# by default, after successful authentication(flow completes) no operation will be performed,
# to apply redirection in case of browsers, provide a list of urls one of which will be used
# after authentication where users will be redirected to.
# this is optional
authorized_redirect_urls: []
# oidc auth server configs
oidc_config:
google:
client_id: "xxxxx.apps.googleusercontent.com"
client_secret: "xxxxx"
issuer_url: "https://accounts.google.com"
# validity of the verification duration
validity: "10m"
mail_otp:
subject: "Frontier - Login Link"
# body is a go template with `Otp` as a variable
body: "Please copy/paste the OneTimePassword in login form.<h2>{{.Otp}}</h2>This code will expire in 15 minutes."
validity: 15m
mail_link:
subject: "Frontier Login - One time link"
# body is a go template with `Otp` as a variable
body: "Click on the following link or copy/paste the url in browser to login.<br><h2><a href='{{.Link}}' target='_blank'>Login</a></h2><br>Address: {{.Link}} <br>This link will expire in 15 minutes."
validity: 15m
# platform level administration
admin:
# bootstrap seeds a superuser service account from config, using a client_id
# and client_secret. Automation such as the GitOps reconcile flow logs in as
# it, so there is always a superuser without needing an existing one. The
# account is created and promoted on every boot, and the secret is rotated if
# you change it here. Log in with: Authorization: Basic base64(client_id:client_secret).
# Leave both empty to turn this off.
bootstrap:
client_id: ""
client_secret: ""
# smtp configuration for sending emails
mailer:
smtp_host: smtp.example.com
smtp_port: 587
smtp_username: "username"
smtp_password: "password"
smtp_insecure: true
headers:
from: "username@acme.org"
# webhook configuration for sending events to external services
webhook:
# encryption key used to encrypt the secrets stored in database not to encrypt
# the webhook payload
encryption_key: "encryption-key-should-be-32-chars--"
# documents a user has to accept before an account is created
consent:
# false (the default) keeps the behaviour frontier had before consent
# existed: ListConsentDocuments returns an empty list and no signup is
# gated. true with no documents fails at boot rather than doing nothing.
enabled: false
# keyed by document id. every document listed here is required at signup,
# and the key is what the client sends back as accepted_document_ids.
# title, version and url are all mandatory: an empty one fails at boot.
# version is opaque: it is compared for equality only, never parsed.
documents:
terms_of_service:
title: "Terms & Conditions"
version: "2026-04-01"
url: "https://example.org/legal/terms/2026-04-01"
privacy_policy:
title: "Privacy Policy"
version: "2026-04-01"
url: "https://example.org/legal/privacy/2026-04-01"
eula:
title: "End User License Agreement"
version: "2026-02-14"
url: "https://example.org/legal/eula/2026-02-14"
# live resources that block a project or organization delete
deletion:
# false (the default) keeps deletes as they are
enabled: false
# a rule per namespace for each delete. a namespace or delete with no
# rule blocks.
resources:
compute/machine: { project: block, organization: allow }
compute/order: { project: block_unless_deletable, organization: block_unless_deletable }
storage/file: { organization: allow }
# metaschema cache configuration
metaschema:
# how often each server reloads the metaschema cache from the database, so a
# change made on one server reaches the others. 0 disables the background
# refresh; the cache is still primed once at startup.
# e.g. 30s, 1m, 5m
refresh_interval: 1m
db:
driver: postgres
url: postgres://frontier:@localhost:5432/frontier?sslmode=disable
max_query_timeout: 500ms
spicedb:
host: spicedb.localhost
pre_shared_key: randomkey
port: 50051
# consistency ensures Authz server consistency guarantees for various operations
# Possible values are:
# - "full": Guarantees that the data is always fresh although API calls might be slower than usual
# - "best_effort": Guarantees that the data is the best effort fresh [default]
# - "minimize_latency": Tries to prioritise minimal latency
consistency: "best_effort"
# check_trace enables tracing in check api for spicedb, it adds considerable
# latency to the check calls and shouldn't be enabled in production
check_trace: false
billing:
# stripe key to be used for billing
# e.g. sk_test_XXXXXXXXXXX
stripe_key: ""
# if true, tax will be calculated automatically by stripe
# before turning it on, make sure you have configured tax rates in stripe
stripe_auto_tax: false
# webhook secret to be used for validating stripe webhooks events
# all the secrets are used to validate the events useful in case of key rotation
stripe_webhook_secrets: []
# default currency to be used for billing if not provided by the user
# e.g. usd, inr, eur
default_currency: ""
# billing customer account configuration
customer:
# automatically create a default customer account when an org is created
auto_create_with_org: true
# name of the plan that should be used subscribed automatically when the org is created
# it also automatically creates an empty billing account under the org
default_plan: ""
# default offline status for the customer account, if true the customer account
# will not be registered in billing provider
default_offline: false
# free credits to be added to the customer account when created as a part of the org
onboard_credits_with_org: 0
# credit_overdraft_product is the product name that should be used to calculate per unit cost
# of the overdraft credits, it uses the first price available for the product
credit_overdraft_product: ""
# plan change configuration applied when a user changes their subscription plan
plan_change:
# proration_behavior can be one of "create_prorations", "none", "always_invoice"
proration_behavior: "create_prorations"
# immediate_proration_behavior can be one of "create_prorations", "none", "always_invoice"
# this is applied when the plan is changed immediately instead of waiting for the next billing cycle
immediate_proration_behavior: "create_prorations"
# collection_method can be one of "charge_automatically", "send_invoice"
collection_method: "charge_automatically"
# product configuration
product:
# seat_change_behavior can be one of "exact", "incremental"
# "exact" will change the seat count to the exact number of users within the organization
# "incremental" will change the seat count to the number of users within the organization
# but will not decrease the seat count if reduced
seat_change_behavior: "exact"
# refresh interval for billing engine to sync with the billing provider
# setting it too low can lead to rate limiting by the billing provider
# setting it too high can lead to stale data in the billing engine
# e.g. 60s, 2m, 30m
refresh_interval:
customer: 1m
subscription: 1m
invoice: 5m
checkout: 1m
This page contains reference for all the application configurations for Frontier.
Version
| version | int | Version number of the Frontier configuration file. | No |
Logging Configuration
| log.level | string | Logging level for Frontier. Possible values debug, info, warning, error, fatal | No |
| log.audit_events | string | Audit level for Frontier. Possible values none, stdout, db | No |
App Configuration
| app.port | Port number for HTTP communication. | 8000 | Yes |
| app.grpc_port | Port number for gRPC communication. | 8001 | Yes |
| app.metrics_port | Port number for metrics reporting. | 9000 | Yes |
| app.host | Host address for the Frontier application. | 127.0.0.1 | Yes |
| app.identity_proxy_header | Header key used for identity proxy. | | |
| app.disable_orgs_listing | If set to true, disallows non-admin APIs to list all organizations. | | No |
| app.disable_users_listing | If set to true, disallows non-admin APIs to list all users. | | No |
| app.cors_origin | Origin value from where CORS is allowed. | | Yes(for Admin UI) |
| app.metaschema.refresh_interval | How often each server reloads the metaschema cache from the database so a change made on one server reaches the others. 0 disables the background refresh. | 1m | No (default: 1m) |
Authentication Configurations
Configuration to allow authentication in Frontier.
| app.authentication.session.hash_secret_key | Secret key for session hashing. | Yes | "hash-secret-should-be-32-chars--" |
| app.authentication.session.block_secret_key | Secret key for session encryption. | Yes | "block-secret-should-be-32-chars-" |
| app.authentication.token.rsa_path | Path to the RSA key file for token authentication. | Yes | "./temp/rsa" |
| app.authentication.token.iss | Issuer URL for token authentication. | Yes | "http://localhost.frontier" |
| app.authentication.callback_urls | External host used for OIDC/Mail link redirect URI. | Yes | "['http://localhost:8000/v1beta1/auth/callback']" |
| app.authentication.oidc_config.google.client_id | Google client ID for OIDC authentication. | No | "xxxxx.apps.googleusercontent.com" |
| app.authentication.oidc_config.google.client_secret | Google client secret for OIDC authentication. | No | "xxxxx" |
| app.authentication.oidc_config.google.issuer_url | Google issuer URL for OIDC authentication. | No | "https://accounts.google.com" |
Consent Configurations
Documents a user has to accept before an account is created. Frontier stores one consent record per signup, copying each document's version and URL into it, and never reads what is behind the URL.
Every document in the map is required at signup, so there is no per-document required flag. The map key is the document id, which is what a client sends back as accepted_document_ids — the key also enforces unique ids, and keeps a single field env-overridable. Config is read at boot, so any change here needs a restart, and the resolved set is logged at startup so a log, rather than the config repository, says what a deployment was serving.
| app.consent.enabled | Switches the whole feature. Disabled, ListConsentDocuments returns an empty list and no signup is gated. Enabled with no documents fails at boot. | false | No (default: false) |
| app.consent.documents.<id>.title | Human readable name, used by the client to label the link. | "Terms & Conditions" | Yes (when enabled) |
| app.consent.documents.<id>.version | Opaque version, copied into the consent record and compared for equality only. Dates, semver or commit SHAs all work. | "2026-04-01" | Yes (when enabled) |
| app.consent.documents.<id>.url | Absolute URL of the document. Frontier never reads what is behind it. | "https://example.org/legal/terms" | Yes (when enabled) |
Deletion Configurations
Live resources that stop a project or an organization from being deleted. Frontier decides from its own resources table and never asks the service that owns a resource.
The map key is the resource namespace, such as compute/machine. Each namespace gives one rule for a project delete and one for an organization delete. A namespace that is not listed, or a delete with no rule, stops that delete. Config is read at boot, so any change here needs a restart.
block | Any live resource stops the delete. The owning service deletes the resource first. |
block_unless_deletable | A live resource stops the delete unless its metadata has "deletable": true. The owning service sets it. |
allow | Never stops the delete. |
Only the boolean true counts as deletable. A missing key, false, or the string "true" stops the delete. A resource update replaces the whole metadata, so the owning service sends deletable on every update.
An unknown key or rule, a namespace with no rules, or a namespace not shaped like service/name fails at boot.
| app.deletion.enabled | Switches the check. Disabled, live resources never stop a delete. Enabled with no resources fails at boot. | false | No (default: false) |
| app.deletion.resources.<namespace>.project | Rule for a project delete. Missing, it stops the delete. | block | No |
| app.deletion.resources.<namespace>.organization | Rule for an organization delete. Missing, it stops the delete. | allow | No |
Admin Configurations
| app.admin.bootstrap.client_id | Client id of the bootstrap superuser service account. Automation such as the GitOps reconcile flow logs in as it. Leave empty to turn it off. | | Optional |
| app.admin.bootstrap.client_secret | Client secret of the bootstrap superuser service account. The secret is rotated when you change it. | | Optional |
Database Configurations
| db.driver | Database driver. Currently supports postgres. | postgres | Yes |
| db.url | Database connection URL. | postgres://username:password@localhost:5432/databaseName?sslmode=disable | Yes |
| db.max_idle_conns | Maximum number of idle database connections. | 10 | No |
| db.max_open_conns | Maximum number of open database connections. | 10 | No |
| db.conn_max_life_time | Maximum connection lifetime. | 10ms | No |
| db.max_query_timeout | Maximum query execution timeout. | 500ms | No |
SpiceDB Configurations
| spicedb.host | string | Hostname or IP address of the SpiceDB service | localhost | Yes |
| spicedb.pre_shared_key | string | Random key for authentication and secure communication with SpiceDB | random_key | Yes |
| spicedb.port | uint | Port number on which the SpiceDB service is listening | 50051 | Yes |
| spicedb.fully_consistent | boolean | Enable consistent API responses (slower but most consistent) | false | No |