π authlocal is the user-sovereign login system.
any website can ask you to sign-in via authlocal. manage identities on your device any time at https://authlocal.org/
Β π cryptographic. passwordless, emailless, provable.
Β π½ user-sovereign. copy and store your keys however you wish.
Β π‘ local-only. app is 100% clientside. keys are on your device.
Β π₯· pseudonymous. seamlessly carry your identity across services.
Β π free and open-source. a protocol, not a product. zero-cost at global scale.
own your identity.
your identity begins with a permanent seed key. don't lose it. don't share it. it's yours, forever.
"keep it secret. keep it safe."
Β Β β gandalf, fellowship of the ring
visit https://authlocal.org/demo/ to see what the authlocal popup looks like.
- install and import
@e280/authlocal. (and@e280/stratafor this demo)npm install @e280/authlocal @e280/strata
import {Auth} from "@e280/authlocal" import {effect} from "@e280/strata"
- create the auth facility. (see auth.ts)
const auth = new Auth()
- react to user session changes. (see user.ts)
effect(() => console.log( auth.user ? `logged in: ${auth.user.id}` : `logged out` ))
- user.id:
"efe064a4ed1ec1763293612627424c0721b82acd009fc666e6915d8edcfe89e6"
proper id you should identify users by. it's actually the ed25519 public key, as 64 hex characters. - user.alias:
"Gandalf the Gray"
customizable nickname. - user.cryptSecret:
"8109ea0663cdf5da134f2a79f218ac2bcdd69750f2db5ceb02b85d066b28917d"
stable end-to-end encryption key. - user.expiresAt:
1785232580494
js milliseconds time at which this session expires.
- user.id:
- start by remembering a previous user session.
await auth.remember()
- perform a login flow with authlocal. (call from a button click)
await auth.loginViaPopup()
- logout immediately.
await auth.logout()
- import address facility.
import {address} from "@e280/authlocal"
const id = "efe064a4ed1ec1763293612627424c0721b82acd009fc666e6915d8edcfe89e6" // for these examples
- address.from, encode a user id into friendly address format.
address.from(id) // "calwak_curlex_H9Nts5YRurzidb8mQHkHH323mMT8d3oReimRzxeLgwRw"
- address.id, decode an address back into a user id.
address.id("calwak_curlex_H9Nts5YRurzidb8mQHkHH323mMT8d3oReimRzxeLgwRw") // "efe064a4ed1ec1763293612627424c0721b82acd009fc666e6915d8edcfe89e6"
- address.emoji, derive a friendly emoji from the user id.
address.emoji(id) // "π¦"
- address.color, derive a friendly color from the user id.
address.color(id) // "oklch(0.8 0.03 136.94)"
- address.moniker, just the first part of the address.
address.moniker(id) // "calwak_curlex"
- encrypt data.
const ciphertext = auth.user.encrypt( new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF]) )
- decrypt data.
const data = auth.user.decrypt(ciphertext)
- sign a testimony token.
const token = auth.user.signTestimony({ data: {exampleCommandToWriteData: 123}, audience: "https://server.e280.org", // your example server expiresAt: Date.now() + 600_000, // 10 minutes })
- verify a testimony token serverside or elsewhere. (note the import path)
import {verifyTestimony, address} from "@e280/authlocal/core" // data is verifiably signed by a valid delegate const testimony = verifyTestimony(token, { allowedIssuers: ["https://app.e280.org"], // your example frontend allowedAudiences: ["https://server.e280.org"], // your example server }) if (testimony.yay) { // check if verification succeeded const {data, proof} = testimony.value const {id} = proof console.log(data.exampleCommandToWriteData) // 123 console.log(id) // "cd967edd1a3a82e142faa5003eda67d167a2b5f76d0e97e8158defe59e2a2c89" console.log(address.from(id)) // "volrad_welsyx_EqXgGh7SEyGzpbUiacCJ7BVpAP1kBePt6THiR8gSTtGx" } else console.error("testimony verification failed")
- your site opens a popup to authlocal and asks for "delegates", which are signed by the user identity's root key. a delegate is a new keypair that comes with a "proof" token which proves that the delegate was signed by the user root. being a keypair in its own right, a delegate can then sign new "testimony" tokens on behalf of the user, which have a verifiable chain-of-custody back to the user root.
- in a standard login flow, your site asks for two delegates: one ephemeral "auth" delegate that expires in 30 days, and one permanent "crypt" delegate for end-to-end encryption. the "auth" delegate can be used to sign new testimonies for any data or request (eg, "i am user abc123 and i want to write data to the server"), which your server can verify.
