🔒 Authlocal.org Developer Readme
Not a developer? See the User Guide instead
🏛️ Federated – your app gets user logins from authlocal.org popup
🔑 Elliptic – identities are @noble/ed25519
keypairs
📱 Clientside – statically deployed, no api servers
📜 Protocol – permissionless integration, do it your way
🥧 Easy as pie – setup your app with two easy snippets
💖 MIT Licensed – totally free and open source
- Try out the example integration live demo here: https://authlocal.org/app/
- Your users click "Login", pick an identity, then boom! — they're logged into your site.
- Next, you can use claim tokens, for your server to verify user requests.
- Pick one of these javascript install techniques
- HTML install technique
Put this script into your html<head>
:<script type="module"> import {install} from "https://authlocal.org/install.bundle.min.js" const auth = await install() auth.on(login => console.log("auth", login)) </script>
- Webdev install technique
Install the package into your project:Write this in your app's js entrypoint (likenpm install @e280/authlocal
main.ts
):import {install} from "@e280/authlocal" const auth = await install() auth.on(login => console.log("auth", login))
- HTML install technique
- Put this stylesheet into your html
<head>
:<link rel="stylesheet" href="https://authlocal.org/themes/basic.css"/>
- Place these new auth elements anywhere in your html
<body>
:<auth-user></auth-user> <auth-button></auth-button>
- Take it for a spin! You can now login, and logout.
Use this technique if you want to make your own UI, and don't want to load any of the authlocal elements.
- Create the Auth object manually, and trigger the initial load from storage:
import {Auth} from "@e280/authlocal" const auth = new Auth() await auth.loadLogin() auth.on(login => console.log("auth", login))
- You can trigger the authlocal popup, prompting the user to login, like this:
await auth.popup()
- but remember, the call must originate from a user action like clicking a button, otherwise the browser's popup blocker will ignore it.
You must never send the login data anywhere, it stays on the user's device.
The login is automatically persisted in localStorage
for 7 days.
The anatomy of a login:
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 (more on this later)
<auth-button></auth-button>
It's a "Login" button, that when clicked, spawns an Authlocal popup.
When the user is logged in, the button changes to a "Logout" button, which when clicked, will log the user out.
In javascript you can listen for logins/logouts via the button like this:
const authButton = document.querySelector("auth-button")
authButton.on(login => console.log("auth", login))
// 👆
// listen to *this* specific button
authButton.auth.on(login => console.log("auth", login))
// 👆
// listen to *any* button
<auth-user></auth-user>
Displays the user's own logged-in identity. Shows nothing when logged-out.
<auth-sigil hex="c9185ef07bc9f24ca856f2a178e59f85d0d53d22a14b26b434b58a22c9a872fb"></auth-sigil>
Take a hex-encoded id, and present to the user as a sigil.
If the user hovers over the sigil, the full thumbprint is shown in the tooltip.
If the user clicks the sigil, the full thumbprint is copied to the clipboard.
- The purpose of a login is to sign claims on the user's behalf.
- You can then send claims to your server, and verify them.
- "...they want to post this message"
- "...they want to change their avatar"
- "...they want to buy this microtransaction"
- Stuff like that.
- Claims contain cryptographic proof that they stem from a user's login.
- No attacker can forge a claim for somebody else's identity.
import {Time} from "@e280/authlocal"
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"
- You can verify claims on the clientside or serverside.
- You must specify what
appOrigins
you expect to receive claims from (this prevents phishing attacks).
Authlocal gives your app a login session keypair, and a proof token signed by the user's identity keypair.
Your frontend can then create a claim — like "user orders a large pizza" — signed by the session keypair.
Your server verifies the proof, then the claim — proving the user authorized the session, and the session authorized the claim.
- Authority — the website that provides login sessions (authlocal.org)
authorityOrigin
is the provider's origin, eghttps://authlocal.org
- App — the third party website receiving login sessions (your website)
appOrigin
is your app origin, eghttps://e280.org
- Keypair — an ed25519 keypair
.id
is the public key (64 character hex string).secret
is the private key (64 character hex string)
- Identity — a keypair with a label string
- Seed — text snippet or
.seed
file that stores an identity - Nametag — the public data associated with a user's identity
.id
is the public key (64 character hex string).label
is a nickname (max 32 character string)
- Thumbprint — easier-to-read version of an id
thumbprint
=>dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA
sigil
(first two words) =>dozmut.winpex
preview
(first four words) =>dozmut.winpex.linner.forsep
bulk
(second part) =>KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA
- Login — a login session
- is private, should never leave the user's device
.nametag
contains the identity's id and label.expiresAt
js 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
.nametag
contains the identity's id and label.sessionId
proves 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)
💁 Notice:
Authlocal uses a number of utilities from our library@e280/stz
,
To interact with these, you should import them from stz manually.
import {Thumbprint} from "@e280/stz"
- id to thumbprint
Thumbprint.fromHex("005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed") // "dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA"
- id to sigil
Thumbprint.sigil.fromHex("005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed") // "dozmut.winpex"
- thumbprint to id
Thumbprint.toHex("dozmut.winpex.linner.forsep.KgisJ8Pdgey1HC4o8cG59NaLYSoRTiHfA") // "005636bab2c73223ccf56f8112432212f57f01ef61452762cd142acd61ed44ed"
- Seeds can be copy-pasted, or live in a
my-identity.seed
file. Seed text looks like this:"mopfed.nimrut" linler.torhul.datmyn.binwep dilmyr.lagruc.nopwyl.witfur fasnes.sonpes.fostyr.foddur datter.diswyl.dotfer.wannul nomsum
- There can be any number of seeds in the text
- Whitespace and funky characters are ignored. this is a valid seed:
""linlertorhuldatmynbinwepdilmyrlagrucnopwylwitfurfasnessonpesfostyrfoddurdatterdiswyldotferwannulnomsum
- Seeds have three parts:
- the label is a handy nickname that the user assigned, expressed in json format.
"mopfed.nimrut"
- the 256-bit ed25519 private key, expressed as 16 bytename words.
linler.torhul.datmyn.binwep dilmyr.lagruc.nopwyl.witfur fasnes.sonpes.fostyr.foddur datter.diswyl.dotfer.wannul
- the 2-byte sha256 checksum ensures the private key wasn't mistyped.
nomsum
- the label is a handy nickname that the user assigned, expressed in json format.
When you sell a service or digital goods to a user's Authlocal identity, you should have a recovery mechanism, or people will get cranky.
💖 Authlocal is free and open source
- Authlocal is an https://e280.org/ project.
- Open github issues or discussions if you have any questions.
- Like the project? Star it on github, it's the only way we're paid.