Why: two questions about operating this turned up two gaps. "Where do I get the admin password" had no answer once the line scrolled out of the log, and "how do I set up OIDC" ran straight into a sign-in link that could not work. What: - /oidc/login with no parameters now signs a browser in and ends in a session cookie. It previously required the user code of a waiting client, so the link on the web sign-in page always failed. With a code it still approves a device, and the two paths no longer overlap: an empty user code matches no pending device. - POST /api/v1/auth/password, `keeporg passwd`, and a form on /web/vaults. Changing a password requires the current one, and the one-time code when a second factor is enrolled, and revokes that account's other sessions. Until now nothing could change a password, which made the advice printed at first start impossible to follow. - keeporgd -reset-admin, for when that first password was not kept: a new one printed once, any second factor cleared, sessions revoked. It writes the state document directly and says to stop the server first. - The client read stdin through a new buffered reader per prompt, so the first prompt swallowed the rest and anything asking twice could not be scripted. One shared reader now. A prompt for a password being set no longer reads $KEEPORG_PASSWORD either; that variable holds the password you sign in with, and taking it here would have set the new password to the old one. - HANDOVER gains a first-sign-in section and an OIDC setup section covering the redirect URI, the config block, both entry points and how an identity becomes an account. Proved: OIDC now has tests, against a stub provider that serves discovery, authorization, token and userinfo. They cover the web sign-in that was broken, device approval, linking an existing account by username, the refusal when auto_create is off, and a forged callback state. Eight more cover the password change. Checked by hand with the real binaries: the first-start password logs once and works, -reset-admin replaces it while the old one stops working, and `keeporg passwd` changes it from a pipe. Server 0.5.0, desktop clients 0.3.0.
KeepOrg
A synchronization adapter for KeePass. Your databases stay ordinary .kdbx
files that KeePassXC, KeePass2 or KeePassDX opens directly; a server keeps
them in step between everyone who has access.
When two people save at once, the server can merge both edits: it opens the two copies in memory, folds them together by KeePass's own rules and stores the result. Nothing is lost, and no one has to reconcile two files by hand.
Merging means decrypting, so a merge vault's password is kept on the server, encrypted under a master key held outside the data directory. That makes the server part of your trust boundary. Vaults on any other conflict strategy keep their key off the server entirely, exactly as before.
- Server (
keeporgd, Linux): hosts many KDBX databases, controls access with a tree of user groups, accepts registrations by invite link or OIDC, merges concurrent edits, and pushes updates to connected clients. Its web page at/webis for creating a vault and setting its password. - Desktop client (
keeporg, Linux, macOS, Windows, BSD): mirrors every assigned database into one directory as a real file, pushes each save and applies what others push. - Android client: the same, published to every file picker as a storage provider.
No third-party dependencies, no cgo, no FUSE. The KDBX 4 codec, including ChaCha20, BLAKE2b and Argon2, is part of the repository and is tested against both the relevant RFCs and a real KeePassXC.
Quick start
make check # gofmt, vet, tests
make all # keeporgd and keeporg for this host
# a server for trying it out, on 127.0.0.1:8765
KEEPORG_ADMIN_PASSWORD=dev-password-1 make run-server
# in another shell
build/linux-arm64/keeporg login -server http://127.0.0.1:8765 -user admin
build/linux-arm64/keeporg groups
build/linux-arm64/keeporg vault -create "Team Vault" -group <group-id>
build/linux-arm64/keeporg run
Team Vault.kdbx appears in ~/KeepOrg; open it in KeePassXC with the vault
password you just set. Every save is pushed, and a save that races with a
colleague's is merged rather than refused.
Or open http://127.0.0.1:8765/web and create the vault from the browser.
Packaging
make deb # Debian packages for the client and the server
make docker # server container image, scratch-based, about 9 MB
make dmg # macOS disk image with an /Applications symlink (on macOS)
make windows # Windows zip with a Task Scheduler job
make android # unsigned release APK (needs the Android SDK)
make help # every target
Running the server in a container:
head -c 32 /dev/urandom | base64 > master.key
podman secret create keeporg_master_key master.key
podman run -d -p 8765:8765 \
--secret keeporg_master_key \
-e KEEPORG_MASTER_KEY_FILE=/run/secrets/keeporg_master_key \
-e KEEPORG_ADMIN_PASSWORD=change-me \
-v keeporg-data:/var/lib/keeporg \
keeporgd:latest -addr :8765 -data /var/lib/keeporg -url https://keeporg.example.com
Keep that master key: it unwraps the vault keys, and without it the server
can no longer merge. KEEPORG_MASTER_KEY takes the base64 key directly if
your secret store injects variables instead of files. See
packaging/docker/compose.yaml.
Documentation
- docs/HANDOVER.md — architecture, the decisions behind it, operations, and what is left to do.
- docs/PROTOCOL.md — the HTTP API.
- android/README.md — the Android module.