Go app for capturing and archiving HSA-eligible receipts: OIDC/PKCE auth against Authelia, SQLite storage with dual-write (filesystem + DB blob), mobile-first upload, and DB export. Adds AI receipt classification: a config.json catalog of people and categories (seeded into the DB on startup), a prompt builder that derives name-order/initial variants from the data (with same-surname ambiguity handling), and an Anthropic tool-use client behind POST /classify. Tests run against a mock endpoint; a live integration test is env-gated to the cheapest model. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.5 KiB
Authelia OIDC Client Setup
One-time setup. Do this before running the app for the first time.
Step 1 — Generate the OIDC client secret
Run secret.sh on your Authelia host (needs openssl + authelia in PATH):
bash secret.sh
Output looks like:
=== Plaintext secret (app .env → OIDC_CLIENT_SECRET) ===
xK9mP2...64chars...
=== Authelia hash (configuration.yml → client_secret) ===
$argon2id$v=19$m=65536,t=3,p=4$...
Step 2 — Save the plaintext secret
The plaintext secret is only shown once. Save it immediately to the app's env file on the LXC where the app will run:
# /etc/hsa/hsa.env (create this file, chmod 600, owned by the service user)
OIDC_CLIENT_SECRET=xK9mP2...64chars...
Full env file contents are documented in the app's README once we get there.
For now just save OIDC_CLIENT_SECRET=<value> somewhere safe.
Never commit this file to git. .gitignore already excludes .env files.
Step 3 — Generate the OIDC signing key (RSA / RS256)
Authelia needs a signing key for the JWTs it issues. It must be RSA (RS256) — OIDC mandates RS256 as the baseline and Authelia rejects Ed25519/EdDSA for the OIDC JWKS.
Generate it and place it in the secrets dir, owned by the Authelia service user so the
process can read it (it runs non-root; a root-owned chmod 600 key gives
permission denied):
sudo mkdir -p /tmp/oidc-rsa
sudo authelia crypto pair rsa generate --bits 2048 --directory /tmp/oidc-rsa
sudo install -o authelia -g authelia -m 600 /tmp/oidc-rsa/private.pem /etc/authelia/secrets/oidc_jwks.pem
sudo rm -rf /tmp/oidc-rsa
(Confirm the owner matches your other secrets: ls -l /etc/authelia/secrets/. Substitute
if it's not authelia:authelia.)
Step 4 — Add the jwks + client block to configuration.yml
The key is referenced from the .pem file via Authelia's template filter, so it never gets copied into the config. This requires enabling the template filter (see the note after the block — it's a one-line systemd env var).
In configuration.yml, the full identity_providers.oidc section should look like this
(append the hsa-tracker entry if you already have other clients):
identity_providers:
oidc:
jwks:
- key_id: 'main'
algorithm: 'RS256'
use: 'sig'
key: {{ secret "/etc/authelia/secrets/oidc_jwks.pem" | mindent 10 "|" | msquote }}
clients:
- client_id: 'hsa-tracker'
client_name: 'HSA Receipt Tracker'
client_secret: '$argon2id$v=19$...' # the hash from secret.sh
public: false
authorization_policy: 'two_factor'
require_pkce: true
pkce_challenge_method: 'S256'
redirect_uris:
- 'https://hsa.maisym.com/callback'
- 'http://localhost:8080/callback' # for local dev testing
scopes:
- 'openid'
- 'profile'
- 'email'
- 'groups'
response_types:
- 'code'
grant_types:
- 'authorization_code'
token_endpoint_auth_method: 'client_secret_basic'
userinfo_signed_response_alg: 'none'
Required: enable the template config filter
The {{ secret ... }} syntax above only works when Authelia's template config filter
is enabled — it's OFF by default. If you skip this, the {{ ... }} is passed to the YAML
parser raw and breaks the entire config file (symptom: yaml: invalid map key plus a
cascade of "X not configured" errors — those cascade errors are a red herring caused by
the file failing to parse).
Enable the filter on the service:
sudo systemctl edit authelia
Add, save, exit:
[Service]
Environment=X_AUTHELIA_CONFIG_FILTERS=template
Confirm it registered before restarting:
systemctl cat authelia | grep -i filter # should show your Environment line
Then restart (env changes need a full restart, not reload):
sudo systemctl restart authelia
Gotchas worth knowing
- The key must be RSA and readable by the Authelia service user. Ed25519 is rejected
by the OIDC JWKS (RS256 is mandatory). A root-owned
chmod 600key gives the processpermission denied— keep it in/etc/authelia/secrets/owned byauthelia. authelia config validaterun manually shows false positives forjwt_secretandstorage encryption_key, because the*_FILEsecrets are injected by systemd and aren't present in a manual shell. Under the running service they're fine — only trust thejournalctloutput after a real restart for those two.
Step 5 — Create the hsa-users group and add both users
In your Authelia users file (typically users_database.yml), add hsa-users to the groups list for each user:
users:
jm:
disabled: false
displayname: 'JM'
password: '$argon2id$...'
email: 'jm@jmopines.com'
groups:
- 'admins'
- 'hsa-users'
Repeat for the second user.
Step 6 — Restart Authelia
Use restart, not reload — config-file and environment changes are only picked up on a
full restart. (The users/groups file in Step 5 is auto-reloaded by Authelia, but a restart
covers everything at once.)
sudo systemctl restart authelia
Verify it came up clean (no level=error or level=fatal lines):
journalctl -u authelia -n 20
Verification
Once the app is running, opening http://localhost:8080 (or https://hsa.maisym.com) should
redirect you to auth.maisym.com. After login + YubiKey 2FA it should land on a page showing
your identity and [hsa-users] group.