🗽 Authduo.org – Free Auth for Everybody
Authduo.org is an app where users can create and manage digital login passports.
You can add a "Login with Authduo" button to your website, allowing users to login using an Authduo passport.
🔑 Passwordless – passports are cryptographic keypairs
🗽 User-sovereign – users can directly download their passport files
🥷 Privacy-focused – users can be anonymous: no emails, no tracking
💖 Free and open source – zero cost at worldwide scale
🥞 Easy as pancakes – paste in a tiny amount of code to get logins
📱 Clientside – statically hosted on github pages, no api servers
🏛️ Federated – get login tokens from the authduo.org popup flow
🌐 Decentralized – fork and self-host if you'd rather
📜 Protocol – permissionless integration, you can do it your way
Pre-release: Authduo is an unfinished prototype, use at your own risk.
🪪 Authduo.org Login Button
Try out the login button at the Federated Test Page
Choose this installation method if you don't know any better.
-
Insert this in your
<head>
:<script type="module" src="https://authduo.org/install.bundle.min.js"></script> <script type="module"> document.querySelector("auth-button").auth.onChange(login => { if (login) console.log("logged in", login) else console.log("logged out") }) </script>
- Customize that second script to handle logins/logouts your way.
- When the user logs in, the
login
object looks like this:login.name // Cetdok Pizafoaba login.thumbprint // "0d196fc3..." login.expiry // 1731740481065
- When the user logs out,
login
isnull
.
-
Put these elements in your
<body>
:<auth-user></auth-user> <auth-button></auth-button>
- This provides a nice little status/button ui for users to login or logout.
- The login state is automatically stored in
localStorage
.
Choose this installation method if you're familiar with npm, package.json, typescript – stuff like that.
-
Install the npm package
npm i @authduo/authduo
-
Register components and listen for auth changes.
main.ts
import {Auth, components, register_to_dom} from "@authduo/authduo" register_to_dom(components) const auth = Auth.get() auth.onChange(login => { if (login) console.log("logged in", login) else console.log("logged out") })
-
Throw down some elements.
index.html
<auth-user></auth-user> <auth-button></auth-button>
💁 Authduo.org is for convenience, not vendor lock-in
- You can fork Authduo to make your own passport management app, and users can take their passport files there instead
- You can point the login button to your own fork:
<auth-button src="https://authduo.org/"></auth-button>
- Just swap
https://authduo.org/
with your own url - This is what "decentralized", "user-sovereign", and "protocol" is all about
- Just swap
🌠 The More You Know, about Authduo.org
- They'll just generate new passports.
- If you associate important services to your users' passports, you should provide a recovery mechanism so users can re-associate those services with new passports.
- While Authduo's core must stay lean to retain user-sovereignty and privacy, we can still build optional services which allow users to trade a little sovereignty for some conveniences:
- Username and password logins
- Email-based recovery
- OTP/QR codes to easily transfer passports across devices
- Two-factor auth
- You can use
auth.popup
to trigger a login, but you should do this in reaction to a user input event, otherwise the browser will block the popup.import {auth} from "@authduo/authduo" myButton.onclick = async() => { const login = await auth.popup("https://authduo.org/") if (login) console.log("logged in", login) }
- When a user on your app clicks to login, this opens an Authduo.org popup for them to login.
- The authduo signs some tokens with your user's passport keypair, and sends them back to your application.
- Your app receives a
Login
object, which has some useful things:-
login.proof.token
-- this is aProof
token and it's public, so you can send it around anywhere so your user can prove their identity -
login.keys.signClaimToken(~)
-- you can use this to sign arbitrary data into a token, which is verifiably signed on behalf of the user's passport
-
-
Sign a fresh claim token.
import {Future} from "@authduo/authduo" const idToken = await login.keys.signClaimToken({ expiresAt: Future.hours(24), // you can pack any abitrary data you want into this token data: { username: "Rec Doamge", avatarId: "d15aea1a", // perhaps we want to scope this claim to a specific game session, // so that it cannot be stolen by other users and reused in other // game sessions. gameSessionId: "9c22b17e", }, })
-
Send this idToken along with the user's proofToken.
await sendElsewhere(login.proof.token, idToken)
- Each
login
object comes with a proof token that is required to verify any claim tokens.
- Each
-
Verify the proof and claim
import {Proof, Claim} from "@authduo/authduo" receiveElsewhere(async(proofToken, idToken) => { // the origin of your site that triggered the authduo popup const allowedAudiences = ["https://example.benev.gg"] // verifying the proof const proof = await Proof.verify(proofToken, {allowedAudiences}) // proving the claim const claim = await Claim.verify(proof, idToken) // here's that data you packed into the claim console.log(claim.data.username) // "Rec Doamge" console.log(claim.data.avatarId) // "d15aea1a" console.log(claim.data.gameSessionId) // "9c22b17e" // user passport public thumbprint, the true user identifier console.log(claim.thumbprint) // "a32e638e..." console.log(proof.thumbprint) // "a32e638e..." })
- The same proof can be used to verify multiple claims from the same login.
💖 Authduo is free and open source
- I built Authduo because I wanted free user-centric auth for my apps.
- Got questions or feedback? Don't hesitate to open a github issue or discussion anytime.
- My name is Chase Moskal, ping me on discord: https://discord.gg/BnZx2utdev