# Silo Authentication User Guide ## Logging In ### Username and Password Navigate to the Silo web UI. If authentication is enabled, you'll be redirected to the login page. Enter your username and password. This works for both local accounts and LDAP/FreeIPA accounts — Silo tries local authentication first, then LDAP if configured. ### Keycloak / OIDC If your deployment has OIDC enabled, the login page will show a "Sign in with Keycloak" button. Click it to be redirected to your identity provider. After authenticating there, you'll be redirected back to Silo with a session. ## Roles Your role determines what you can do in Silo: | Role | Permissions | |------|-------------| | **viewer** | Read all items, projects, schemas, BOMs. Manage own API tokens. | | **editor** | Everything a viewer can do, plus: create/update/delete items, upload files, manage BOMs, import CSV, generate part numbers. | | **admin** | Everything an editor can do, plus: user management (future), configuration changes. | Your role is shown as a badge next to your name in the header. For LDAP and OIDC users, the role is determined by group membership or token claims and re-evaluated on each login. ## API Tokens API tokens allow the FreeCAD plugin, scripts, and CI pipelines to authenticate with Silo without a browser session. Tokens inherit your role. ### Creating a Token (Web UI) 1. Click **Settings** in the navigation bar 2. Under **API Tokens**, enter a name (e.g., "FreeCAD workstation") and click **Create Token** 3. The raw token is displayed once — copy it immediately 4. Store the token securely. It cannot be shown again. ### Creating a Token (CLI) ```sh export SILO_API_URL=https://silo.kindred.internal export SILO_API_TOKEN=silo_ silo token create --name "CI pipeline" ``` Output: ``` Token created: CI pipeline API Token: silo_a1b2c3d4e5f6... Save this token — it will not be shown again. ``` ### Listing Tokens ```sh silo token list ``` ### Revoking a Token Via the web UI settings page (click **Revoke** next to the token), or via CLI: ```sh silo token revoke ``` Revocation is immediate. Any in-flight requests using the token will fail. ## FreeCAD Plugin Configuration The FreeCAD plugin reads the API token from two sources (checked in order): 1. **FreeCAD Preferences**: `Tools > Edit parameters > BaseApp/Preferences/Mod/Silo > ApiToken` 2. **Environment variable**: `SILO_API_TOKEN` To set the token in FreeCAD preferences: 1. Open FreeCAD 2. Go to `Edit > Preferences > General > Macro` or use the parameter editor 3. Navigate to `BaseApp/Preferences/Mod/Silo` 4. Set `ApiToken` to your token string (e.g., `silo_a1b2c3d4...`) Or set the environment variable before launching FreeCAD: ```sh export SILO_API_TOKEN=silo_a1b2c3d4... freecad ``` The API URL is configured the same way via the `ApiUrl` preference or `SILO_API_URL` environment variable. ## Default Admin Account On first deployment, configure a default admin account to bootstrap access: ```yaml # config.yaml auth: enabled: true local: enabled: true default_admin_username: "admin" default_admin_password: "" # Set via SILO_ADMIN_PASSWORD env var ``` ```sh export SILO_ADMIN_PASSWORD= ``` The admin account is created on the first startup if it doesn't already exist. Subsequent startups skip creation. Change the password after first login via the database or a future admin UI. ## Configuration Reference ### Minimal (Local Auth Only) ```yaml auth: enabled: true session_secret: "" # Set via SILO_SESSION_SECRET local: enabled: true default_admin_username: "admin" default_admin_password: "" # Set via SILO_ADMIN_PASSWORD ``` ### LDAP / FreeIPA ```yaml auth: enabled: true session_secret: "" local: enabled: true default_admin_username: "admin" default_admin_password: "" ldap: enabled: true url: "ldaps://ipa.kindred.internal" base_dn: "dc=kindred,dc=internal" user_search_dn: "cn=users,cn=accounts,dc=kindred,dc=internal" user_attr: "uid" email_attr: "mail" display_attr: "displayName" group_attr: "memberOf" role_mapping: admin: - "cn=silo-admins,cn=groups,cn=accounts,dc=kindred,dc=internal" editor: - "cn=silo-users,cn=groups,cn=accounts,dc=kindred,dc=internal" - "cn=engineers,cn=groups,cn=accounts,dc=kindred,dc=internal" viewer: - "cn=silo-viewers,cn=groups,cn=accounts,dc=kindred,dc=internal" tls_skip_verify: false ``` ### OIDC / Keycloak ```yaml auth: enabled: true session_secret: "" local: enabled: true oidc: enabled: true issuer_url: "https://keycloak.kindred.internal/realms/silo" client_id: "silo" client_secret: "" # Set via SILO_OIDC_CLIENT_SECRET redirect_url: "https://silo.kindred.internal/auth/callback" scopes: ["openid", "profile", "email"] admin_role: "silo-admin" editor_role: "silo-editor" default_role: "viewer" ``` ### CORS (Production) ```yaml auth: cors: allowed_origins: - "https://silo.kindred.internal" ``` ## Environment Variables | Variable | Description | Config Path | |----------|-------------|-------------| | `SILO_SESSION_SECRET` | Session encryption key | `auth.session_secret` | | `SILO_ADMIN_USERNAME` | Default admin username | `auth.local.default_admin_username` | | `SILO_ADMIN_PASSWORD` | Default admin password | `auth.local.default_admin_password` | | `SILO_OIDC_CLIENT_SECRET` | OIDC client secret | `auth.oidc.client_secret` | | `SILO_LDAP_BIND_PASSWORD` | LDAP service account password | `auth.ldap.bind_password` | | `SILO_API_URL` | API base URL (CLI and FreeCAD) | — | | `SILO_API_TOKEN` | API token (CLI and FreeCAD) | — | Environment variables override config file values. ## Troubleshooting ### "Authentication required" on every request - Verify `auth.enabled: true` in your config - Check that the `sessions` table exists in PostgreSQL (migration 009) - Ensure `SILO_SESSION_SECRET` is set (empty string is allowed for dev but not recommended) - Check browser cookies — `silo_session` should be present after login ### API token returns 401 - Tokens are case-sensitive. Ensure no trailing whitespace - Check token expiry with `silo token list` - Verify the user account is still active - Ensure the `Authorization` header format is exactly `Bearer silo_` ### LDAP login fails - Check `ldaps://` URL is reachable from the Silo server - Verify `base_dn` and `user_search_dn` match your FreeIPA tree - Test with `ldapsearch` from the command line first - Set `tls_skip_verify: true` temporarily to rule out certificate issues - Check Silo logs for the specific LDAP error message ### OIDC redirect loops - Verify `redirect_url` matches the Keycloak client configuration exactly - Check that `issuer_url` is reachable from the Silo server - Ensure the Keycloak client has the correct redirect URI registered - Check for clock skew between Silo and Keycloak servers (JWT validation is time-sensitive) ### Locked out (no admin account) If you've lost access to all admin accounts: 1. Set `auth.local.default_admin_password` to a new password via `SILO_ADMIN_PASSWORD` 2. Use a different username (e.g., `default_admin_username: "recovery-admin"`) 3. Restart Silo — the new account will be created 4. Log in and fix the original accounts Or directly update the database: ```sql -- Reset a local user's password (generate bcrypt hash externally) UPDATE users SET password_hash = '', is_active = true WHERE username = 'admin'; ``` ### FreeCAD plugin gets 401 - Verify the token is set in FreeCAD preferences or `SILO_API_TOKEN` - Check the API URL points to the correct server - Test with curl: `curl -H "Authorization: Bearer silo_..." https://silo.kindred.internal/api/items`