- Trustless — No server or DB; key from a shared identifier (
connectorId) both sides agree on. - Connector-bound — Same
connectorId= same pair; others can’tdecodeorverify. - Request, decode, verify —
request→decodetocodeId→verifywith user input (number or digits). - Time-bound — Payloads expire automatically and predictably in 1–60 seconds (configurable).
- Session ID —
hashIdcan be one-time per session (default) or stable per user for repeated identity proof.
Note
Prerequisites: For Deno install from deno.com. For npm use Node.js (e.g. nodejs.org).
npm:
npm install @neabyte/trustless-idDeno (JSR):
deno add jsr:@neabyte/trustless-idUse a connector ID (connectorId) (e.g. service URL or app identifier) on both sides. Generate a one-time hashId via generate(connectorId), create an instance via create(connectorId), build a requestId via request(hashId, expireTime?), then client decodes to a numeric code (codeId) to show the user; verifier checks the user-entered code with verify(requestId, secret).
import trustless from '@neabyte/trustless-id'
// Connector ID (same on both sides)
const connectorId = 'trustless://auth/example.com:0.1.0?service=none'
// One-time hashId per session
const hashId = trustless.generate(connectorId)
// Instance for connector (same on client and verifier)
const instance = trustless.create(connectorId)
// Build payload; send requestId to verifier (QR / link / form)
const requestId = instance.request(hashId, 10)
// Client decodes to get code (show to user so they can type it at verifier)
const codeId = instance.decode(hashId, requestId)
if (codeId !== null) {
console.log('Code:', codeId)
// Verifier side: check user-entered secret
console.log('Verify:', instance.verify(requestId, codeId))
}| Aspect | TOTP | Trustless-ID |
|---|---|---|
| Secret | A shared secret is generated and stored by both the server and the user (e.g. in an authenticator app). | No stored secret. Only a connector ID (connectorId) (e.g. service URL or app identifier) is agreed on; the key is derived from it when needed. |
| Code derivation | Code is computed from the shared secret and the current time window (e.g. 30s) using HMAC-SHA1. | Code is derived from the session’s hashId and the encoded requestId using a FNV-1a–style mix; time is embedded in the request payload. |
| Server / backend | A server (or backend) must store the secret per user and validate the code on each login. | No server or database. Client uses same connectorId to derive key, decode to code; verifier uses same connectorId to verify the user-entered code locally. |
| Typical use | Two-factor authentication (2FA): prove that the user possesses the shared secret at login time. | One-time pairing or repeated identity: same connector; client uses request → decode → code, verifier uses verify. Use a new hashId per session (anonymous) or one stable hashId per user (repeated proof, no server storage). |
- USAGE.md — Full API, flow, and type reference; how to use the library end-to-end and every method.
- USECASE.md — Use cases to clarify flow and architecture (actors, channels, secure vs leak conditions).
From the repo root (requires Deno).
Check — format, lint, and typecheck source:
deno task checkUnit tests — format/lint tests and run all tests:
deno task testTests live under tests/ (Trustless flow, Cipher, Security, Expiration, EdgeCases).
This project is licensed under the MIT license. See the LICENSE file for details.