Who can sign in
Every orangecheck account signs in to your app by default, however it was made: email, Google, GitHub or a Bitcoin wallet. To keep bots out, you can let in only accounts backed by bitcoin. The person has backed their account with one coin they hold (bonds). The coin stays in their wallet, and you never see it: your token carries only floors, when the coin was last checked, and a nullifier for your app.
1. Set the floor
Open your project on ochk.app and choose Use
orangecheck sign-in. That is the project's Sign-in tab: How people sign
in, then Who can sign in below it. Pick a minimum amount and age, for
example 100,000 sats unspent 30 days. The lowest floor is 1,000 sats: ochk.io
won't take a smaller coin. The floor is saved in the project and served,
uncached, at GET https://me.ochk.io/api/integrator/<project_key>/sign-in.
2. Enforce it on your server
import { withOcAuth } from '@orangecheck/me-client/server';
export default withOcAuth(
async (req, res) => {
if (!req.ocSession) return res.status(401).json({ ok: false });
res.status(200).json({ ok: true, did_oc: req.ocSession.did_oc });
},
{
audience: 'https://yourapp.example',
projectKey: process.env.OC_PROJECT_KEY!,
}
);
A change in your settings is enforced within a minute. An account below the floor gets:
403 {
"ok": false,
"reason": "bond_required",
"need": { "min_sats": 100000, "min_days": 30 },
"have": { "sats_floor": 10000, "days_floor": 90 },
"back_url": "https://ochk.app/me/account#backing"
}
Link that person to back_url, where they can back their account. have is
null when no coin backs it. If your requirement has never been readable, the
request gets 503 bond_policy_unavailable rather than being let through
unchecked. A projectKey that names no project gets 500 unknown_project_key
(me-client 0.32 and later).
ochk.io re-checks the coin when its last check is over ten minutes old, and
every claim says when that was (oc_bond.checked_at). You can't ask for a fresh
check, but you can refuse a stale one with maxAgeSecs, which only code sets.
In code, requireBond: { minSats, minDays, maxAgeSecs } does the same as the
project setting and wins over projectKey. readBondClaim(session) and
bondMeets(session, { minSats, minDays, maxAgeSecs }) come from
@orangecheck/me-client/server (or @orangecheck/auth-core) for your own
checks: a fast lane, a higher free tier, a ban list.
3. Keep one account per nullifier
oc_bond.nullifier is the same for the same coin at your app every time, and
only ochk.io can compute it, so it doesn't reveal the coin. Keep one account per
nullifier: that is the real bot check at your site. A floor says some coin backs
the account; the nullifier tells you whether that coin already backed another
account of yours. Ban a nullifier to ban the coin.
A coin backs one account at a time. Released from one account, it can back a
different one only 30 days later. Sites on *.ochk.io share one family session,
so they share one nullifier.
Requires @orangecheck/me-client ≥ 0.27.3. back_url and the snake_case need
arrive in 0.28.0.