3.10 Configure application.ini

All application settings — secrets, URLs, DB credentials, tunables — live in src/main/backend/application.ini. The bld build copies this file into the WAR (work/exploded/WEB-INF/backend/) on every build; the servlet reads it once at load via MainServlet.getEnvironment(). Edit the source-tree copy, then rebuild and redeploy.

The repo ships application.ini.example (a redacted template) and gitignores application.ini itself, so your live secrets never end up in commits. First-time setup is a copy + edit:

cp src/main/backend/application.ini.example src/main/backend/application.ini
$EDITOR src/main/backend/application.ini

Required:

[main]

DatabaseType     = PostgreSQL
DatabaseHost     = localhost
DatabasePort     = 5432
DatabaseName     = ownsona
DatabaseUser     = ownsona
DatabasePassword = <PGPW>

EMBEDDING_ENDPOINT     = https://api.openai.com/v1/embeddings
EMBEDDING_API_KEY      = sk-...your-OpenAI-key...
EMBEDDING_MODEL        = text-embedding-3-small
EMBEDDING_DIMENSIONS   = 1536

OWNSONA_LOGIN_USERNAME = <pick-any-username>
OWNSONA_LOGIN_PASSWORD = <pick-a-strong-password>

# OAuth 2.1 (resource server + embedded authorization server).
# OAuthAuthorizationServer is the single URL that drives everything:
# the resource identifier, the AS issuer, and the JWKS URI all derive
# from it.  Use the full URL with scheme.
OAuthAuthorizationServer = https://<your-host>
OAuthAsEnabled           = true

3.10.1 What OWNSONA_LOGIN_USERNAME and OWNSONA_LOGIN_PASSWORD are

These are credentials you invent when setting up the server — a username and password that guard the OwnSona OAuth consent page. They are not tied to any external service: not your OpenAI / Anthropic / Google account, not your Unix login, not anything else. They exist nowhere outside application.ini and the OwnsonaUserAuthenticator class that reads them.

The single flow they’re used in: when someone (you) connects an MCP client like Claude or ChatGPT to your OwnSona server, the client opens a browser tab to https://your-host/oauth/authorize. That page asks for OWNSONA_LOGIN_USERNAME and OWNSONA_LOGIN_PASSWORD. You type them in, click Allow on the consent screen, and the OwnSona authorization server issues an OAuth access token + refresh token back to the client. The client uses those for every subsequent MCP call. After the first time the user doesn’t see the login page again until the refresh token expires (30 days by default).

Because OwnSona is single-user, one username/password pair is enough. Pick anything you’ll remember. Treat the password like any other password (strong, not reused). Both values sit in plaintext in application.ini alongside the database password and the embedding API key; keep the file chmod 600.

3.10.2 What the OAuth* keys do

They turn on the resource server (validates incoming Authorization: Bearer JWT access tokens) and the embedded authorization server (issues those JWTs at /oauth/authorize and /oauth/token, with dynamic client registration at /oauth/register). MCP clients discover both via auto-served metadata documents at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.

The resource server discovers the JWKS URI automatically via the RFC 8414 metadata document the AS publishes; no separate JWKS key is needed. The resource identifier and the AS issuer URL also default to OAuthAuthorizationServer.

3.10.3 Where the AS keeps its signing key (OAuthAsIniFile)

The authorization server persists its signing key, dynamically- registered clients, and refresh tokens to a single INI file. By default it lives at WEB-INF/backend/oauth.ini under the deployed Tomcat — but this default is strongly inadvisable for production. The deployed WAR’s WEB-INF/backend/ directory is replaced on every WAR redeploy: any file written there at runtime is overwritten with whatever the build packaged. In practice that means every ./bld war + cp ROOT.war ... silently rotates the AS signing key, invalidating every issued access token and forcing every MCP client through the browser OAuth flow again.

The fix is one config line. Choose a path outside the Tomcat webapps tree, owned and writable by the service user the JVM runs as (typically ownsona), and set OAuthAsIniFile to that absolute path in application.ini. Common choices:

# In the service user's home directory:
OAuthAsIniFile = /home/ownsona/oauth.ini

# Or a conventional state directory:
OAuthAsIniFile = /var/lib/ownsona/oauth.ini

Create the parent directory if needed and make sure it’s writable by the service user:

# Example for the /var/lib/ownsona option:
sudo install -d -o ownsona -g ownsona -m 700 /var/lib/ownsona

The file itself is created on first AS request; you don’t need to pre-create it. Once it exists, include the chosen location in your backup policy — it holds the AS’s master signing key. Treat it as sensitive as application.ini itself.

A relative value or an omitted OAuthAsIniFile falls back to the WEB-INF/backend/oauth.ini default, which is fine for local development (where there is no redeploy) but should not be left in that state for production.

EMBEDDING_DIMENSIONS must match the vector(N) column type in sql/001_init.sql. The shipped schema uses vector(1536), which matches text-embedding-3-small.

Optional keys with defaults are documented in Configuration.