An open standard for logins you own.
rootcard is a specification with open-source libraries in Rust and JavaScript. It is not a company or a single service: any server can be a home for rootcard identities, and rootcard.org is one of them. This page explains the standard; the specification is the reference.
A username and a password, backed by signatures.
For you it is a username, a password and a card in a drawer. Under the hood, every step is a signature anyone can check.
Create
Pick a username and a password. Your browser makes a recovery key and prints
it as a recovery card. Your id is the SHA-256 of a statement signed by that key, shown to people as
Astra#3F9C.
Choose a home
The recovery key signs an instance: a fresh account key and the server that is your home. That can be rootcard.org, another public home or your own server.
Sign in
Your device proves the password to fetch the vault, unlocks it locally and signs the home's one-time challenge. The password never leaves your device.
Prove
Any service, on any server, can ask you to sign a challenge and check it against your public log. It does not call a central API and does not trust your home's word.
Download and move
Download your whole account as one file at any time. With the recovery card, move it to another home in minutes; your id, handle and password come along.
Recover
Forgot the password or lost a device? The recovery card signs a new instance. Every old password, vault and session stops working at once. Your id stays.
The password is for every day. The recovery card is for everything else.
The format itself enforces the split: only the recovery key can sign changes to who can access the identity, where it lives or whether it exists.
Low power
- Sign in to your home
- Edit your public profile and private data
- Change the password (with the old one)
- Download your account file
- Prove who you are to a service
High power
- Reset a forgotten password
- Add or revoke passwords
- Move to another home, or restore after a loss
- Rotate the recovery key itself
- Retire the identity for good
A safer login for your service. One identity for many.
A standard username-and-password login
Add rootcard to your own server and your users see what they already know: a username, a
password and, once, a recovery card to save. Your server becomes the host with
rootcard-host (Rust); your pages use the npm package. No redirect, no third party, no password
database to leak.
An ID card across websites
Choose a home: rootcard.org, a host run by someone you trust, or your own. Any other service checks who you are by itself, from a fresh proof addressed to it. Your account there is keyed by your account id, which never changes, even when you move.
Create a card with rootcard.org as home →Where it stands.
Against database leaks, replay and lock-in, rootcard does better than password logins and social logins. It does not yet match passkeys against phishing, and it is young.
| Password + hash | Passkeys | "Sign in with …" | rootcard | |
|---|---|---|---|---|
| Server learns the password | At every login | No password | The provider does | Never sent |
| Server database stolen | Offline guessing of hashes | Nothing useful | Provider's database | Offline guessing of the vault (Argon2id, 64 MiB), home only |
| Replay of a login | Session theft | No | Token theft | No: one-time, bound signatures |
| Forgotten password | E-mail reset | Platform recovery | The provider decides | Recovery card only; no backdoor |
| Who controls the identity | The service | The site and your sync provider | The provider | You, through the recovery key |
| Move to another provider | New account | New credential per site | New account | Same id, one key tool operation |
| Phishing | Vulnerable | Resistant | Vulnerable at the provider | Relayed logins fail; a fake page can still capture the password |
| Maturity | Decades | Widely deployed | Widely deployed | New, not yet externally reviewed |
Two libraries and one HTTP binding.
Rust and JavaScript implement the same functions and produce the same bytes, checked against shared test vectors. The JavaScript package has zero dependencies and runs on WebCrypto in browsers and Node 20+. A host never sees a password, never runs Argon2id and verifies logs incrementally.
// Verify a proof from anyone, against their public log import { verifyProof } from "rootcard"; const state = await verifyProof(proof, log, challenge, "https://shop.example", { realms: ["global"], now }); console.log(state.handle); // "Astra#3F9C"