Krywerk Server web administration¶
As of 2026-10-14. Steps W1–W4 of the plan are implemented: sign-in, overview, management, audit log. W5, key operations in the browser, is deliberately missing (section 7). The web administration replaces the web console of the former Boxcryptor company account, as far as that is possible with end-to-end encryption and no keys on the server.
Krywerk Server serves the web administration itself, at https://<server>/verwaltung/. There is no additional
container and no Node build. It is off by default (KRYWERK_SERVER_WEB=1 turns it on).
1. Who sees what¶
| manager (OWNER) | IT administration (role admin) |
everyone else | |
|---|---|---|---|
| Overview with action items | own team folders | all | empty |
| Team folders: members, access, emergency access, events | own | all | – |
| Add members/change role/remove, archive, delete | own | all (can be turned off: web.admin_manage_all) |
– |
| People: list, details, devices, lock/unlock, delete locked people permanently (GDPR) | only themselves (remove devices) | all | only themselves |
| Groups: overview; create, fill and delete own groups | – | yes | – |
| View and cancel emergency requests | own folders | all | – |
| Audit log with filters and CSV export | events of own folders | everything | – |
Roles come from the same token claims as for the API (oidc.roles_claim, oidc.admin_role).
2. Features¶
- Overview: tiles (active/archived folders, people, groups, locked people, open emergency requests), and below them the action items:
- folders in which nobody can grant access (no manager with a set-up account)
- people waiting for approval
- open emergency requests
- locked people who are still listed in folders
- people without a set-up account
The most recent events follow at the bottom. - Team folders: list with search and status filter. The detail page shows: - direct members, with changing the role and “Remove” - search for people and groups, with “As member” / “As manager” - “Who has access”: all people, including via nested groups, each with origin and status (“Access active”, “Waiting for approval”, “Account not set up”, “Locked”) - emergency access, archive/reactivate, delete (archived folders only, after typing the name) and the most recent events
The last manager cannot be removed. - People: list with filters (“Account not set up”, “Locked”), last sign-in and last use of a device. The detail page shows team folders with their origin, groups, devices with “Remove” and the events. Lock person takes effect immediately: - no more sign-in, no more unlocking and no more API requests (403), web sessions ended - optionally remove devices and revoke direct memberships and Krywerk groups - notice about folders whose key the person had, with the recommendation “Renew key” (F10) - Groups: groups from the identity provider are read-only; they are synchronized at every sign-in. Own groups (origin “Krywerk”) can be created, renamed, filled (people and subgroups, without cycles) and deleted here. This is meant for organizations whose identity provider does not supply groups, and corresponds to the groups of the Boxcryptor console. - Emergency access: all requests with justification, approvals and status. Open requests can be canceled. Below them are the folders without emergency access. Setting up and approving stay in the app because they require keys. - Audit log: who changed what and when, from the app, from Cryptomator apps (device registered, key retrieved or denied) and from the web administration (“(Web)”). Filters by period, event, folder and person; CSV export for spreadsheet programs, with protection against formulas.
3. What is deliberately not possible¶
- Granting access, that is, encrypting folder keys for new members, needs the key of a manager. The Krywerk app does that (“Manage → Grant access”). The web administration shows who is waiting.
- Creating team folders needs write access to the cloud folder and therefore happens in the app.
- Viewing files, public links and policies as in Boxcryptor cannot be replicated. The company master key is replaced by visible managers and emergency access.
- Creating people belongs to the identity provider. A person appears after their first sign-in.
4. Setup¶
- Client in the identity provider, client ID
krywerk-verwaltung, authorization code with PKCE S256, redirecthttps://<server>/verwaltung/anmeldung, after sign-outhttps://<server>/verwaltung/abgemeldet. - Keycloak from
compose.keycloak.yaml: the client is already in the realm template; the address comes fromKRYWERK_DOMAIN. - Existing Keycloak: public client with the values above, plus the same group mapper as for the client
cryptomator. - Entra ID directly: app registration (web platform) with this redirect URI and a client secret
(
KRYWERK_SERVER_WEB_CLIENT_SECRET). Roles and groups must be included in the ID token there. - In
krywerk.env:KRYWERK_SERVER_WEB=1, optionallyKRYWERK_SERVER_WEB_CLIENT_ID,…_CLIENT_SECRETor…_CLIENT_SECRET_FILE,…_SESSION_HOURS(8),…_IDLE_MINUTES(30),…_ADMIN_MANAGE_ALL(true). For local times, setTZ=Europe/Berlin(or your time zone). - The Caddy templates allow
/verwaltungonly from private networks. If administration from outside is needed, adjust the@verwaltung_externblock. - Run
krywerk-server check, then openhttps://<server>/verwaltung/.
Audit log settings: KRYWERK_SERVER_AUDIT_RETENTION_DAYS (365; 0 = never delete) and
KRYWERK_SERVER_AUDIT_RECORD_IP (off). The audit log is written even without the web administration.
5. Security¶
- Sign-in as a “backend for frontend”:
- The server performs the authorization code flow with PKCE (S256),
state(bound to a browser cookie) andnonceitself. - It checks the ID token (signature, issuer,
aud/azp= web client,nonce) and the access token like the API. - Tokens are not stored. The browser only receives a session cookie:
HttpOnly,SameSite=Lax, and with HTTPSSecurewith the__Host-prefix. - The database stores only the SHA-256 of the session ID. Sessions end after 8 hours, after 30 minutes without a request, on sign-out and when the person is locked.
- Forms: each with a per-session CSRF token (compared in constant time) and an
Origincheck. Destructive actions have their own confirmation page. - Headers: CSP
default-src 'none'without scripts,frame-ancestors 'none',X-Frame-Options: DENY,Cache-Control: no-store,Referrer-Policy: same-origin.same-originis needed because browsers sendOrigin: nullwithno-referrer; the Caddy templates therefore set their value only if the server sends none. - Output: HTML is produced only through
web::html::Html. Markup is possible there only as a fixed string; everything else is escaped, and a test checks this with names like<img onerror=…>. Redirect targets after sign-in are valid only within/verwaltung/, so nobody can be redirected to foreign sites. - Audit log: never contains keys, JWEs, tokens or setup codes. A test also checks the server log for this.
- API: locked people now also receive 403 there. This deliberately deviates from the reference hub.
6. Tests¶
cargo test -p kw-server:- units: escaping, CSV, redirect targets, audience, configuration, audit log, queries, neutral terms
tests/web.rswith an OIDC stub and PKCE check: sign-in (state, nonce, aud, role, one-time code), headers, permissions, CSRF/Origin, last manager, archive/delete, locking including the effect on the API, removing a device, idle expiry, own groups with cycle protection, canceling an emergency request, audit log/CSV, sign-oute2e/web_e2e.sh(part ofrun_all.sh stack): real Keycloak of the test stack with a client viae2e/hub/web_client.sh, sign-in through the Keycloak form, 26 checks and a server log without tokens/cookies.e2e/server_ops_e2e.shwithKRYWERK_OPS_KEYCLOAK=1:- realm template: client with the redirect from
KRYWERK_DOMAIN, foreign redirects rejected - forwarding behind Caddy
- Caddy keeps
Referrer-Policy: same-origin - Manual (test plan, session E): browser on another computer, phone width, dark mode, keyboard, screen reader spot check.
7. Open¶
- W5 grant access in the browser via the setup code (WebCrypto). Deliberately postponed; decide only once there is experience with the alternative.
- Automatic granting in the app: postponed – since the web of trust, the app deliberately grants access person by person with a visible trust level (DECISIONS.md D-8).
- Signing out of Keycloak without a confirmation prompt: for that, the server would have to send
id_token_hintand therefore store the ID token. Today Keycloak asks once.