porchlight/docs/plans/2026-02-18-config-file-design.md
2026-02-18 12:09:43 +01:00

2.7 KiB

TOML Configuration File Design

Date: 2026-02-18 Status: Approved

Goal

Add a TOML configuration file to Porchlight so that server settings and OIDC client registrations can be defined in a file. Environment variables retain highest priority and override any file-based values.

Decisions

Decision Choice Rationale
File format TOML Human-friendly, supports comments, stdlib tomllib on 3.11+
Integration pydantic-settings TomlConfigSettingsSource Already available in pydantic-settings 2.12, handles precedence natively
Default path porchlight.toml in CWD Simple convention, overridable via OIDC_OP_CONFIG_FILE
Missing file Silently skip Env vars and defaults still work — file is optional
Scope Server settings + client registrations in one file Single source of truth

Precedence

env vars  >  TOML file  >  defaults

pydantic-settings handles this via settings_customise_sources().

Example porchlight.toml

issuer = "https://auth.example.com"
debug = false
session_secret = "a-long-random-string"
sqlite_path = "data/porchlight.db"
signing_key_path = "data/keys"
invite_ttl = 86400

[clients.my-webapp]
client_secret = "super-secret-value"
redirect_uris = ["https://app.example.com/callback"]
response_types = ["code"]
scope = ["openid", "profile", "email"]
token_endpoint_auth_method = "client_secret_basic"

[clients.another-app]
client_secret = "another-secret"
redirect_uris = ["https://other.example.com/oidc/callback"]
response_types = ["code"]
scope = ["openid", "profile"]
token_endpoint_auth_method = "client_secret_basic"

Code Changes

config.py

  • Add ClientConfig(BaseModel) with fields: client_secret, redirect_uris, response_types (default ["code"]), scope (default ["openid"]), token_endpoint_auth_method (default "client_secret_basic").
  • Add config_file: str = "porchlight.toml" field to Settings.
  • Add clients: dict[str, ClientConfig] = {} field to Settings.
  • Override settings_customise_sources() to insert TomlConfigSettingsSource between env and defaults. Use config_file field as the TOML path.

app.py

  • After creating the OIDC server, loop over settings.clients and register each client in oidc_server.context.cdb.
  • Keep the internal manage-app client registration as-is (always registered regardless of config file).

cli.py

  • No changes. Settings() picks up the TOML file automatically.

What Stays the Same

  • All existing OIDC_OP_* env vars work identically.
  • Settings() call sites unchanged.
  • Docker/compose env var configuration unchanged.
  • No new dependencies (pydantic-settings 2.12 already has TOML support, Python 3.13 has tomllib in stdlib).