Card and item
A card is a signed set of items in the user's wallet. Each item has an identifier such as bisotun.main.app.pseudonym (the account ID).
A ready-made web widget shows the QR code and the phone button. Your server signs the request and receives a signed, verified result. You never handle proofs or keys of your users.
A card is a signed set of items in the user's wallet. Each item has an identifier such as bisotun.main.app.pseudonym (the account ID).
Your back end. It is registered with Bisotun under a name, with your RSA public key (recommended) or a shared HMAC secret, and permission for specific items only.
https://cert.bisotun.app. It runs each request, talks to the wallet, verifies the proof and returns the result to you.
@bisotun/frontend, served at /sdk/bisotun.js. It renders the QR code, the "Open Bisotun Wallet" button on phones and the pairing step, in Persian, Arabic and English with right-to-left support.
The browser calls your back end. Your back end builds a disclosure request, signs it as a JWT and posts it to https://cert.bisotun.app/session.
The session server answers with a session pointer, a secret requestor token and a frontend request. You keep the token on your server and return the pointer and frontend request to the widget.
The widget shows the QR code or button. The user opens the request in Bisotun Wallet and shares or declines.
The session server verifies the proof and posts the result, as a JWT signed with its key, to your HTTPS callbackUrl.
Your back end verifies the signature, checks status DONE, proofStatus VALID and each item's status PRESENT, then logs the user in or continues.
The browser never sees your key or the requestor token, and it cannot change what is requested.
<section id="bisotun-form"></section>
<script src="https://wallet.bisotun.app/sdk/bisotun.js"></script>
<script>
bisotun.newWeb({
element: '#bisotun-form',
language: 'en',
session: {
url: '/api/bisotun', // YOUR back end
start: { url: (o) => `${o.url}/start`, method: 'POST' },
result: { url: (o, { sessionToken }) => `${o.url}/result/${sessionToken}` },
},
}).start()
.then((result) => { /* logged in */ })
.catch((endState) => { /* Cancelled, TimedOut, ... */ });
</script>
The developer guide shows the full options, including endpoint paths, a popup variant, theming and the Content Security Policy entries you need. You can also serve the bundle and its fonts/ folder from your own site.
The signed request names the items you need:
{
"iss": "your-requestor-name",
"iat": 1790640000,
"sub": "verification_request",
"sprequest": {
"callbackUrl": "https://your.site/api/bisotun/callback",
"request": {
"@context": "https://wallet.bisotun.app/ld/request/disclosure/v2",
"disclose": [[["bisotun.main.app.pseudonym"]]]
}
}
}
disclose is a list of required items; each can offer alternatives, and each alternative can combine items from one card. You can also require a specific value. Requests older than 5 minutes are refused, so keep your clock in sync.
| Item | Status |
|---|---|
bisotun.main.app.pseudonym — the wallet's account ID, random and the same towards every site |
Available |
bisotun.main.email.address — email address verified by Bisotun |
Coming soon |
| Items of cards issued by other organizations | When those issuers are onboarded |
Write to support@bisotun.app. Tell us your site and the items you need.
Your requestor name, permission for the agreed items, and the session server's public key for checking results. Send us your RSA public key, or receive an HMAC key.
Follow the developer guide, with complete Node.js and Python examples, and compare with the demo, whose main scenario is exactly this passwordless login with the account ID.
status, proofStatus and every item's status check out.Everything you need is in the guide.