π https://authlocal.org/ π
Authlocal is a free login system for the web.
Any website you visit can request your login by opening an Authlocal popup, but your identity seed files stay safely local on your device. You can go to the authlocal.org website any time to manage your identities.
- π½ User-sovereign β you hold your own seed files
- π Cryptographic β no emails, no passwords
- π₯· Privacy-focused β pseudonymous, device-local, no databases
- π Free and open-source β zero-cost at global scale
Own your identity.
When you create an identity, download the seed and keep it safe. The seed is the identity. Don't lose it. Don't share it. Never give your seed to another person or website. It's yours, forever.
- Install authlocal and friends via npm
npm install @e280/authlocal @e280/stz
- Javascript to install Authlocal on your page
import authlocal from "@e280/authlocal" const {auth} = await authlocal.install({ theme: authlocal.themes.basic, }) auth.on(login => { if (login) console.log("logged in", login) else console.log("logged out") })
- Put these new elements in your html
<body><auth-user></auth-user> <auth-button></auth-button>
- Take it for a spin!
You should be able to login and logout via Authlocal.
- Never send the login info anywhere. Send claims instead!
- Logins are auto persisted in localStorage for 7 days
- Anatomy of a
loginobject:login.sessionIdβ id of the login session hex stringlogin.nametag.idβ user identity public key hex stringlogin.nametag.labelβ user's chosen nicknamelogin.expiresAtβ js timestamp of when this login expireslogin.isExpired()β returns true if the login is expired nowlogin.signClaim(options)β sign a claim
The purpose of a login, is that it can sign claims on the user's behalf. You can then send those claims to your server and verify them there. A claim contains a cryptographic proof that it stems from a genuine login session signed by the user's seed.
Spritually, a claim is trying to say something like "This user gave permission to this frontend to now say on their behalf:"
- "we want to post this message..."
- "we want to change their avatar..."
- "we want to buy this microtransaction..."
import {Time} from "@e280/stz"
const claimToken = await login.signClaim({
// any json-friendly data you want
claim: {message: "i love ice cream"},
// when should this claim expire?
expiresAt: Time.future.hours(24),
})import {verifyClaim} from "@e280/authlocal/core"
const {claim, proof} = await verifyClaim({
claimToken,
appOrigins: ["https://e280.org"],
// |
// your website origin goes here
})proof.sessionId
// id for this login session, looks like:
// "ff730fe2d725aa5210152975212d1068d7fe28ae22b5e62337a4cde42215187a"proof.nametag.id
// user identity id, looks like:
// "a08263e70a0a48a07e988a7c0931ada6b0a38fa84bf367087b810c614a4c2070"proof.nametag.label
// user identity nickname, looks like:
// "Michael Scott"Thumbprintis an@e280/stztool for visualizing 64-char idsimport {Thumbprint} from "@e280/stz"
- id to full thumbprint
Thumbprint.fromHex("005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed") // "dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA"
- id to short sigil
Thumbprint.sigil.fromHex("005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed") // "dozmut.winpex"
- thumbprint to id
Thumbprint.toHex("dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA") // "005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed"
- Authority β the website that provides login sessions (authlocal.org)
authorityOriginis the provider's origin, eghttps://authlocal.org
- App β the third party website receiving login sessions (your website)
appOriginis your app origin, eghttps://e280.org
- Keypair β an ed25519 keypair
.idis the public key (64 character hex string).secretis the private key (64 character hex string)
- Identity β a keypair with a label string
- Seed β text snippet or
.seedfile that stores an identity - Nametag β the public data associated with a user's identity
.idis the public key (64 character hex string).labelis a nickname (max 32 character string)
- Thumbprint β easier-to-read version of an id
thumbprint=>dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfAsigil(first two words) =>dozmut.winpexpreview(first four words) =>dozmut.winpex.linner.forsepbulk(last part) =>KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA
- Login β a login session
- is private, should never leave the user's device
.nametagcontains the identity's id and label.expiresAtjs time of the moment this login expires.isExpired()returns true if the login is now expired.signClaim(options)sign a claim
- Proof β provenance for login
- is a token signed by an identity
- is public, can be shared around
.nametagcontains the identity's id and label.sessionIdproves a login session is blessed by an identity
- Claim β arbitrary claim your frontend can make
- is a token signed by the login session, verifiable on your server
- is public, can be shared around
- includes the proof token (thus nametag and sessionId)
- includes any arbitrary claim data you want
- verified by
verifyClaim(options)
π§βπ» Authlocal is an e280 project
Open github issues or discussions if you have any questions.
Star us on github, it's the only way we're paid.
Free and open source.