nano133

Build · nano133 Kit

Sign in with a passkey. Get a Nano purse.

Face ID, a fingerprint or the device PIN. The passkey makes a small Nano wallet, a purse, on the person's own device, and the purse signs them in. No password, no email, and your site stores no key.

  • Face ID, a fingerprint or a PIN
  • No password
  • The site stores no key
  • A Nano address for each person

Live on nano133. Try it below, or press "Sign in" on any page and pick "Passkey".

With a passkey

Make a purse, and sign in

  1. Make a passkey.One press on “Make a passkey”.
    What your device asks

    Your device asks for Face ID, a fingerprint or the device PIN. No password to type, and no email to give. A password manager can hold the passkey too.

  2. Open my purse.One more press, “Open my purse”, and your device asks a second time.
    Why two prompts

    That use of the passkey works out the purse’s key, on your device. So making a purse is two prompts with a button between them; later it is one.

    The same purse each time

    The same passkey gives the same purse each time.

  3. Keep a spare key.The code is a second key to the same purse. Without the passkey and without this code, the purse and the Nano in it are lost.
    When the page offers it

    Before you are signed in, the page offers the purse’s code once: “Show my code” or “Later”. Write it down and keep it off the device.

  4. Signed in.The purse signs one short message. Nothing is sent to the site but a signature.
    What it costs

    It is not a payment, and it costs nothing.

The next time

  • One prompt. "Use my passkey" asks your device once and opens the same purse. A browser that still holds the purse signs in with its purse tile, and the device is not asked.
  • "I have a passkey" or "Make a new one". Where a page is about to make a purse, and this browser has not used a passkey yet, it asks this first. A second passkey is a second, empty purse, so a person who has one must not make one by mistake. Where the site makes new passkey purses, a third button sits under the two, here and under "Use my passkey" and "Make a passkey" in the sign-in sheet: "Make a purse in this browser only". That purse has no passkey: its key stays in this browser. It stops one time at "Back up your purse's code", and the page still reminds you until you save the code.

Try it

No money is needed.

Checking…

Where is my key?

Ӿyour deviceyour passkeyno keythe site
  • On your device. The purse's key is made there and used there. It is never sent to the site.
  • With your passkey. Apple, Google or a password manager can keep the passkey and copy it to your other devices. By the design, the purse comes with it: the same passkey, the same purse. A passkey does not cross from one maker to another by itself: an iPhone's passkey reaches a Windows PC by a QR scan with the phone, or through a password manager. not tested by us yet
  • Not with the site. No password table, no key and no copy of the purse. A stolen database holds nothing that opens a purse.

One site, one purse

shop.examplegame.exampleӾӾ

A passkey works only on the site that made it. So a person has a different purse, with a different Nano address, on each site that uses this kit. Two sites cannot link one person by an address. Each purse is its own small wallet: money in one is not in the other.

Is it safe?

It is safer than a password, and it is not magic. Here is what this design stops, and what it does not. Treat a purse in a browser like the cash in your pocket: enough to play and to pay, not your savings.

It protects you from
A stolen or reused passwordThere is no password.
A fake copy of the site (phishing)A passkey answers only to the real address of the site. A fake site gets nothing from it.
A stolen database of the siteThe site holds no key and no copy of a purse.
Someone who finds your locked phoneThe passkey needs your face, your finger or your PIN.
It does not protect you from
A virus or a bad browser extension on your own deviceIt can see what the page sees while the purse is open.
A site that is hacked, or that turns badIts own page handles the purse after you unlock it. This is true of every wallet in a browser.
A lost passkey, with no saved recovery codeNobody can open the purse then: not you, and not the site.
Someone who can unlock your phoneTo the phone, they are you.

Keep your device clean

The purse is as safe as the device it is on. Seven habits do most of the work.

  1. Update

    Keep the system and the browser up to date.

  2. Few extensions

    Keep only the browser extensions you need, from makers you know.

  3. A screen lock

    A face, a finger or a PIN on every device that has your passkey.

  4. Passkey sync on

    Let your phone maker or password manager keep the passkey, so a lost phone is not a lost purse. A passkey on a security key stays on that key.

  5. The recovery code on paper

    Write it down once and keep it away from the device. It is the only other way in.

  6. Play money only

    Keep small amounts in a browser purse. Keep larger amounts in a wallet app or a hardware wallet.

  7. Check the address

    Look at the address bar before you tap. The real site, with the lock, and no other.

If you lose the passkey

  • Two ways back in. The passkey that your provider kept for you, or the purse's code that you wrote down at "Keep a spare key".
  • No third way. The site has no key, so the site cannot help. Without the passkey and without the code, the purse and the Nano in it are lost.

For your site: ten lines

Your page asks for a passkey on your own domain, gets a Nano address and a signature, and your server checks that one signature. You store an address. You never store a key.

import { signinMessage } from "@nano133/signin/message";          // safe for a browser
import { checkSignatureSignin } from "@nano133/signin/signature";  // your server

// In the browser, on a tap: the purse from the passkey signs one short message.
const at = Date.now();
const message = signinMessage("shop.example", address, at);  // your own domain is in the text
const signature = purse.sign(message);                       // the purse from the passkey: not in the package yet

// Send three short values to your server:
await fetch("/signin/signature", { method: "POST", body: JSON.stringify({ address, at, signature }) });

// On your server: one check, no secret and no user table.
const account = await checkSignatureSignin({ domain: "shop.example", useOnce }, { address, at, signature });

A sketch of the kit's code. nano133 runs this design in its own sign-in sheet. The two functions with a name here are in @nano133/signin today, from 0.2.1. The purse from a passkey is not in the package yet.

  • No server secret. Your server checks one signature. It needs no key of its own and no table of passwords.
  • Your domain, and all of it. A passkey belongs to your domain, and any page on a subdomain of it can ask for that passkey. So every subdomain must be your own.
  • Where the browser cannot do it. Some older phones and browsers cannot make a purse from a passkey. A password manager's extension can answer in a form that the page does not read: one such form (a list of 32 numbers) is read, others are refused. A browser that reports the function can still fail. The page then says so in plain words and makes nothing weaker in its place. You can still sign in with a wallet that signs, or use a purse that lives in this browser.

With a wallet you already have: a signature

The kit has this today. A person signs in with a Nano wallet they already have: the wallet signs a short message, and your site checks the signature. It needs a wallet that can sign a message.

Three wallets have a sign-in request of their own today: Berry Wallet, Nautilus and NanChat. Your page shows a link or a QR code, the wallet shows your site's name and signs, and the wallet sends the signature to your site.

Your wallet signs

example.com: sign in as nano_1you…r4ccount at 1790000000000

No XNO needed. The message names the site, so it can't sign you in anywhere else.

A wallet that can sign messages proves its key, for free.

With a signature

How it works

  1. Your page writes a short message.Its domain, the account and the time.
  2. Their wallet signs the message.With its key.
  3. Your site checks the signature.And it signs that browser in.

No payment is sent. A signature counts only when it names your site, is fresh (5 minutes) and was not used before.

What it costs

Security

Set it up with AI

Paste this into Claude, ChatGPT, Gemini or your coding agent, in your site's repository:

Add "Sign in with Nano" to this site: people sign in with their Nano (XNO)
wallet, which signs a short message. No password, no email, and no payment.
Use the npm package @nano133/signin and follow its SPEC step by step:
https://nano133.com/build/sign-in-with-nano/SPEC.md
Ask me for the site's domain. Never print, log or commit a key or secret.
Test with the package's memory store first.

The agent follows the step-by-step spec. Claude Code users can install the add-sign-in-with-nano skill from the nano133 Kit.

For developers

Set it up by hand

  1. Choose your domain.Exactly as people see it: the message names it, so a signature for your site counts nowhere else.
  2. Install the package.@nano133/signin
  3. Choose a once-only store.A row with a unique key, so a signature counts one time. The Firestore one, or your own.
  4. Add the route.It checks the signature and gives the address. Rate-limit it.POST /signin/signature
  5. On sign-in, create a new session.And show “Signed in as nano_…”.
  6. Test it.With the package’s memory store, then with one real sign-in.