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
OWNSONA_LOGIN_USERNAME and OWNSONA_LOGIN_PASSWORD areOAuth* keys doOAuthAsIniFile)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.
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.
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.