signet-verify 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +111 -0
- package/README.md +110 -40
- package/llms.txt +28 -15
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.7.2 (2026-10-16)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- correct the published docs against the source (#49) (docs)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 0.7.1 (2026-09-25)
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- default cross-device relay to nos.lol (#46)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## 0.7.0 (2026-09-11)
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- default to the Signet relay and export it as DEFAULT_RELAY_URL (#44) (verify)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## 0.6.1 (2026-09-11)
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
- fail with relay-refused when the relay closes the subscription (#43) (auth)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
## 0.6.0 (2026-09-11)
|
|
36
|
+
|
|
37
|
+
### Features
|
|
38
|
+
|
|
39
|
+
- one anchor for the sign-in deadline, and tell the user about it (#42) (auth)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## 0.5.2 (2026-09-10)
|
|
44
|
+
|
|
45
|
+
### Bug Fixes
|
|
46
|
+
|
|
47
|
+
- let a restarted wait keep its original subscription window (#41) (auth)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## 0.5.1 (2026-09-08)
|
|
52
|
+
|
|
53
|
+
### Bug Fixes
|
|
54
|
+
|
|
55
|
+
- replay auth responses after mobile app switching (#39)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
## 0.5.0 (2026-06-05)
|
|
60
|
+
|
|
61
|
+
### Features
|
|
62
|
+
|
|
63
|
+
- surface bunkerUri from the auth response (cross-device signer upgrade)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## 0.3.1 (2026-05-03)
|
|
68
|
+
|
|
69
|
+
### Bug Fixes
|
|
70
|
+
|
|
71
|
+
- bump to publish 0.3.0 displayName feature to npm (#11) (release)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## 0.3.0 (2026-05-03)
|
|
76
|
+
|
|
77
|
+
### Features
|
|
78
|
+
|
|
79
|
+
- surface displayName from AuthResponse, sanitised (#9) (auth)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
## 0.2.2 (2026-05-03)
|
|
84
|
+
|
|
85
|
+
### Features
|
|
86
|
+
|
|
87
|
+
- `SignetAuthResult.displayName?: string` — surfaces the user's persona handle when they opted to share it on the approval screen. Mirrors the `display_name` URL param delivered by the redirect-back flow. Sanitised on receipt: control + bidi characters stripped, capped at 64 chars, empty values dropped.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## 0.2.1 (2026-04-18)
|
|
92
|
+
|
|
93
|
+
### Bug Fixes
|
|
94
|
+
|
|
95
|
+
- use published signet-protocol@^1.6.0, not file:../signet (deps)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## 0.2.0 (2026-04-18)
|
|
100
|
+
|
|
101
|
+
### Features
|
|
102
|
+
|
|
103
|
+
- reshape signet-verify as a proper ESM npm package
|
|
104
|
+
- waitForAuthResponse SDK helper for cross-device login
|
|
105
|
+
- initial release of signet-verify — drop-in age verification SDK
|
|
106
|
+
|
|
107
|
+
### Bug Fixes
|
|
108
|
+
|
|
109
|
+
- bump esbuild to ^0.25.12 (GHSA-67mh-4wv8-2f99) (deps)
|
|
110
|
+
|
|
111
|
+
|
package/README.md
CHANGED
|
@@ -10,8 +10,11 @@ npm install signet-verify
|
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
|
+
Script tag (the IIFE bundle exposes `window.Signet`; the version is pinned, so change `0.7.1` to upgrade):
|
|
14
|
+
|
|
13
15
|
```html
|
|
14
|
-
<
|
|
16
|
+
<button id="verify-btn">Verify your age</button>
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/signet-verify@0.7.1/dist/signet-verify.iife.js"></script>
|
|
15
18
|
<script>
|
|
16
19
|
document.getElementById('verify-btn').addEventListener('click', async () => {
|
|
17
20
|
const result = await Signet.verifyAge('18+');
|
|
@@ -23,17 +26,26 @@ npm install signet-verify
|
|
|
23
26
|
}
|
|
24
27
|
});
|
|
25
28
|
</script>
|
|
26
|
-
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
ESM (bundler, browser only, since `verifyAge` opens a modal):
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { verifyAge } from 'signet-verify';
|
|
35
|
+
|
|
36
|
+
const result = await verifyAge('18+');
|
|
37
|
+
if (!result.verified) console.log('Not verified:', result.error);
|
|
27
38
|
```
|
|
28
39
|
|
|
29
40
|
## How It Works
|
|
30
41
|
|
|
31
42
|
1. Website calls `Signet.verifyAge('18+')`
|
|
32
|
-
2. A modal
|
|
33
|
-
3.
|
|
34
|
-
4. The
|
|
35
|
-
5.
|
|
36
|
-
|
|
43
|
+
2. A modal opens. The SDK builds a `signet-verify-request` (request ID, required age range, `relayUrl`, timestamp) but the modal shows only a truncated text placeholder, `signet:verify:` plus the first 40 characters of the base64 payload, not a rendered QR code. Those 40 characters stop before the request ID and the relay URL
|
|
44
|
+
3. The modal listens on a `BroadcastChannel` named `signet-verify-<requestId>`. It opens no WebSocket and never reads from a relay. The proof must arrive as a `signet-verify-response` message carrying that request ID on that channel, so whatever posts it has to run in the same origin and browser profile as the page
|
|
45
|
+
4. The SDK checks the credential's signature, expiry and age range, then asks the verification bot about the verifier's professional registration
|
|
46
|
+
5. Returns the result
|
|
47
|
+
|
|
48
|
+
To receive a response from another device over a relay, use `waitForAuthResponse` (see below); `verifyAge` does not do that.
|
|
37
49
|
|
|
38
50
|
## Verifier Trust
|
|
39
51
|
|
|
@@ -59,56 +71,79 @@ const result = await Signet.verifyAge('18+', { verifierCheckUrl: null });
|
|
|
59
71
|
|
|
60
72
|
## Cross-device Sign-in-with-Signet
|
|
61
73
|
|
|
62
|
-
`verifyAge`
|
|
74
|
+
`verifyAge` resolves with a `SignetVerifyResult` and reports failures in `result.error` rather than rejecting. `waitForAuthResponse` resolves with a `SignetAuthResult` on success and rejects with an `Error` whose `message` and `code` are the failure code (see below). Their `timeout` options also differ: for `verifyAge` it is how long the modal waits before resolving with `error: 'timeout'`; for `waitForAuthResponse` it is an optional, earlier give-up.
|
|
75
|
+
|
|
76
|
+
`verifyAge` is the same-browser modal flow: its response arrives on a
|
|
77
|
+
`BroadcastChannel`, never over a relay. For a cross-device sign-in,
|
|
63
78
|
a consumer minting its own challenge, opening the auth URL or QR on one
|
|
64
79
|
device, and waiting on a relay for the response published from the user's
|
|
65
|
-
phone
|
|
80
|
+
phone, use `waitForAuthResponse` directly:
|
|
66
81
|
|
|
67
82
|
```ts
|
|
68
|
-
import {
|
|
83
|
+
import { schnorr } from '@noble/curves/secp256k1.js'; // install @noble/curves yourself; the SDK does not re-export it
|
|
84
|
+
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
85
|
+
import { waitForAuthResponse, DEFAULT_RELAY_URL } from 'signet-verify';
|
|
86
|
+
|
|
87
|
+
// 1. Ephemeral session keypair. The private key must be a 32-byte Uint8Array;
|
|
88
|
+
// a hex string is rejected with `invalid-session-privkey`.
|
|
89
|
+
const sessionPrivKey = schnorr.utils.randomSecretKey();
|
|
90
|
+
const sessionPubkey = bytesToHex(schnorr.getPublicKey(sessionPrivKey));
|
|
91
|
+
|
|
92
|
+
// 2. The challenge: 32 random bytes as 64-character hex. This is the `requestId`.
|
|
93
|
+
const requestId = bytesToHex(crypto.getRandomValues(new Uint8Array(32)));
|
|
69
94
|
|
|
70
|
-
// Stamp this ONCE, when you mint the challenge and open the auth URL / show the QR.
|
|
95
|
+
// 3. Stamp this ONCE, when you mint the challenge and open the auth URL / show the QR.
|
|
71
96
|
const issuedAt = Math.floor(Date.now() / 1000);
|
|
72
97
|
|
|
98
|
+
// 4. The auth URL (render it as a QR code or a link). The parameters mirror
|
|
99
|
+
// examples/cross-device-login.html; `relay` must match `relayUrl` below.
|
|
100
|
+
const signetAppUrl = 'https://signet-app.example'; // placeholder: your Signet app's origin
|
|
101
|
+
const authUrl = signetAppUrl + '/?' + new URLSearchParams({
|
|
102
|
+
auth: '1',
|
|
103
|
+
challenge: requestId,
|
|
104
|
+
origin: location.origin,
|
|
105
|
+
name: 'My Site',
|
|
106
|
+
callback: location.origin + '/callback', // unused in relay mode, still required
|
|
107
|
+
t: String(issuedAt),
|
|
108
|
+
relay: DEFAULT_RELAY_URL,
|
|
109
|
+
sessionPubkey,
|
|
110
|
+
}).toString();
|
|
111
|
+
|
|
112
|
+
// 5. Wait for the response. Call controller.abort() to cancel.
|
|
113
|
+
const controller = new AbortController();
|
|
73
114
|
const result = await waitForAuthResponse({
|
|
74
|
-
requestId,
|
|
75
|
-
relayUrl,
|
|
76
|
-
sessionPrivKey,
|
|
115
|
+
requestId,
|
|
116
|
+
relayUrl: DEFAULT_RELAY_URL,
|
|
117
|
+
sessionPrivKey,
|
|
77
118
|
expectedOrigin: location.origin,
|
|
78
|
-
issuedAt, //
|
|
119
|
+
issuedAt, // pass on EVERY call for this sign-in, including retries
|
|
120
|
+
abortSignal: controller.signal,
|
|
79
121
|
});
|
|
80
122
|
```
|
|
81
123
|
|
|
82
124
|
### The sign-in deadline
|
|
83
125
|
|
|
84
126
|
A cross-device sign-in has exactly one deadline: `issuedAt + AUTH_FRESHNESS_WINDOW_SEC`.
|
|
85
|
-
Past that point, this library
|
|
86
|
-
to it.
|
|
127
|
+
`AUTH_FRESHNESS_WINDOW_SEC` is `300` seconds (5 minutes). Past that point, this library
|
|
128
|
+
stops listening and reports `expired`, so show a countdown to it.
|
|
87
129
|
|
|
88
130
|
```ts
|
|
89
|
-
import {
|
|
90
|
-
|
|
91
|
-
// Stamp this ONCE, when you mint the challenge and open the auth URL / show the QR.
|
|
92
|
-
const issuedAt = Math.floor(Date.now() / 1000);
|
|
93
|
-
const expiresAt = issuedAt + AUTH_FRESHNESS_WINDOW_SEC; // show a countdown to this
|
|
131
|
+
import { AUTH_FRESHNESS_WINDOW_SEC } from 'signet-verify';
|
|
94
132
|
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
relayUrl: DEFAULT_RELAY_URL, // the Signet relay — must match the relay= in your auth URL
|
|
98
|
-
sessionPrivKey,
|
|
99
|
-
expectedOrigin: location.origin,
|
|
100
|
-
issuedAt, // ← pass on EVERY call for this sign-in, retries included
|
|
101
|
-
abortSignal, // ← optional; cancels the wait and closes the subscription
|
|
102
|
-
});
|
|
133
|
+
const expiresAt = issuedAt + AUTH_FRESHNESS_WINDOW_SEC; // unix seconds; count down to this
|
|
134
|
+
const secondsLeft = () => Math.max(0, expiresAt - Math.floor(Date.now() / 1000));
|
|
103
135
|
```
|
|
104
136
|
|
|
137
|
+
The `timeout` option is in milliseconds. Leave it out when you pass `issuedAt`: the
|
|
138
|
+
wait then lasts until the deadline above.
|
|
139
|
+
|
|
105
140
|
**Pass `issuedAt` on every call, including a restart.** On mobile the page is
|
|
106
141
|
suspended the moment it hands off to the signer app. A wait restarted without the
|
|
107
142
|
anchor asks the relay only for responses newer than the restart — which silently
|
|
108
143
|
excludes the one published while you were backgrounded, and it is never asked for
|
|
109
144
|
again. This was a real, 100%-reproducible failure before 0.5.2.
|
|
110
145
|
|
|
111
|
-
**Distinguish the failures.** The rejection message is:
|
|
146
|
+
**Distinguish the failures.** The rejection is an `Error` whose message is one of:
|
|
112
147
|
|
|
113
148
|
| Code | Meaning | What to offer |
|
|
114
149
|
|---|---|---|
|
|
@@ -116,9 +151,11 @@ again. This was a real, 100%-reproducible failure before 0.5.2.
|
|
|
116
151
|
| `timeout` | The wait gave up early — an explicit shorter `timeout`, or no `issuedAt` was supplied at all | A retry, anchored to the same `issuedAt` |
|
|
117
152
|
| `denied` | The user rejected the request | Nothing; respect it |
|
|
118
153
|
| `aborted` | You aborted via `abortSignal` | Nothing |
|
|
119
|
-
| `relay-error` | The socket failed | A retry, anchored to the same `issuedAt` |
|
|
154
|
+
| `relay-error` | The socket failed. Rejected only where there is no `document` (a non-browser runtime); in a browser the wait reconnects while the page is visible and gives up with `timeout` or `expired` | A retry, anchored to the same `issuedAt` |
|
|
155
|
+
| `relay-closed` | The socket closed. Same rule as `relay-error` | A retry, anchored to the same `issuedAt` |
|
|
120
156
|
| `relay-refused` | The relay closed the subscription — `err.reason` has its text (e.g. `auth-required`) | A relay that serves gift wraps to an unauthenticated reader. `relay.damus.io` currently does not; `nos.lol` (the default) does |
|
|
121
|
-
| `invalid-issued-at` | `issuedAt` looks like the wrong unit (e.g. milliseconds) or is too far in the future | A bug in your code, not a retry
|
|
157
|
+
| `invalid-issued-at` | `issuedAt` looks like the wrong unit (e.g. milliseconds) or is too far in the future | A bug in your code, not a retry; check you're passing unix **seconds** |
|
|
158
|
+
| `invalid-request-id`, `invalid-session-privkey`, `invalid-relay-url`, `invalid-expected-origin` | The matching option failed validation before any connection was made | A bug in your code, not a retry; see the option table below |
|
|
122
159
|
|
|
123
160
|
The code is on both `err.message` and `err.code` — branch on either.
|
|
124
161
|
|
|
@@ -127,17 +164,17 @@ precedence over `issuedAt`. Prefer `issuedAt`, which derives it correctly.
|
|
|
127
164
|
|
|
128
165
|
## API
|
|
129
166
|
|
|
130
|
-
### `
|
|
167
|
+
### `verifyAge(requiredAgeRange, options?)` (`Signet.verifyAge` in the IIFE build)
|
|
131
168
|
|
|
132
|
-
Returns `Promise<SignetVerifyResult
|
|
169
|
+
Returns `Promise<SignetVerifyResult>`. Failures are reported in `result.error`, not as a rejection.
|
|
133
170
|
|
|
134
171
|
**Options:**
|
|
135
172
|
|
|
136
173
|
| Option | Type | Default | Description |
|
|
137
174
|
|--------|------|---------|-------------|
|
|
138
|
-
| `relayUrl` | `string` | `DEFAULT_RELAY_URL` (`wss://nos.lol`) |
|
|
175
|
+
| `relayUrl` | `string` | `DEFAULT_RELAY_URL` (`wss://nos.lol`) | Written into the `relayUrl` field of the request object `verifyAge` builds. `verifyAge` never connects to it, the response does not travel over it (it arrives on a `BroadcastChannel`), and the text the modal shows does not include it. The kind-1059 gift-wrap requirement under `waitForAuthResponse` therefore does not apply to this option |
|
|
139
176
|
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Modal colour scheme |
|
|
140
|
-
| `timeout` | `number` | `120000` | Timeout in milliseconds |
|
|
177
|
+
| `timeout` | `number` | `120000` | Timeout in milliseconds, clamped to 5000 to 600000 |
|
|
141
178
|
| `verifierCheckUrl` | `string \| null` | `'https://verify.signet.forgesworn.dev'` | Verification bot URL. Set to `null` to skip. |
|
|
142
179
|
| `acceptUnconfirmed` | `boolean` | `false` | Accept credentials from unconfirmed verifiers |
|
|
143
180
|
|
|
@@ -162,11 +199,43 @@ Returns `Promise<SignetVerifyResult>`
|
|
|
162
199
|
|-------|---------|
|
|
163
200
|
| `'cancelled'` | User cancelled the verification |
|
|
164
201
|
| `'timeout'` | Verification timed out (default: 2 minutes) |
|
|
202
|
+
| `'invalid-age-range'` | `requiredAgeRange` is not one of the five values under Age Range Values; no modal is shown |
|
|
165
203
|
| `'invalid-credential'` | Credential signature failed verification |
|
|
204
|
+
| `'credential-expired'` | The credential's `expires` time has passed |
|
|
166
205
|
| `'age-range-not-met'` | Credential age range doesn't satisfy the requirement |
|
|
167
206
|
| `'verifier-not-confirmed'` | Verifier is not confirmed against a public register |
|
|
168
207
|
| `'verifier-check-unavailable'` | Verification bot unreachable (credential valid but verifier status unknown) |
|
|
169
208
|
|
|
209
|
+
### `waitForAuthResponse(options)` (`Signet.waitForAuthResponse` in the IIFE build)
|
|
210
|
+
|
|
211
|
+
Returns `Promise<SignetAuthResult>`. It resolves with the verified result and rejects with an `Error` on failure; `err.code` is one of the codes in the failure table under Cross-device Sign-in-with-Signet.
|
|
212
|
+
|
|
213
|
+
**Options (`WaitForAuthOptions`):**
|
|
214
|
+
|
|
215
|
+
| Option | Type | Required | Default | Description |
|
|
216
|
+
|--------|------|----------|---------|-------------|
|
|
217
|
+
| `requestId` | `string` | yes | none | The challenge sent in the auth URL: 64-character hex (32 bytes) |
|
|
218
|
+
| `relayUrl` | `string` | yes | none | The relay you subscribed on. `wss://`, or `ws://` for `localhost` and `127.0.0.1` only |
|
|
219
|
+
| `sessionPrivKey` | `Uint8Array` | yes | none | Ephemeral session private key, 32 bytes. Used to unwrap the NIP-17 response |
|
|
220
|
+
| `expectedOrigin` | `string` | yes | none | Your origin (scheme, host and optional port), verbatim. Must match the `origin` tag of the signed auth event |
|
|
221
|
+
| `issuedAt` | `number` | no, but pass it | none | Unix **seconds** when you minted the challenge. Anchors the relay query and the deadline. More than 300 seconds in the future rejects with `invalid-issued-at` |
|
|
222
|
+
| `timeout` | `number` | no | Remaining validity (`issuedAt + 300` seconds minus now) when `issuedAt` is set, otherwise `120000` | Milliseconds, clamped to 5000 to 600000. Use it only to give up earlier than the default |
|
|
223
|
+
| `since` | `number` | no | `issuedAt - 60` when `issuedAt` is set, otherwise now minus 60 | Raw relay query anchor in unix seconds. Takes precedence over `issuedAt` |
|
|
224
|
+
| `abortSignal` | `AbortSignal` | no | none | Aborts the wait and closes the subscription; rejects with `aborted` |
|
|
225
|
+
|
|
226
|
+
**Result (`SignetAuthResult`):**
|
|
227
|
+
|
|
228
|
+
| Field | Type | Description |
|
|
229
|
+
|-------|------|-------------|
|
|
230
|
+
| `pubkey` | `string` | The user's pubkey (64-character hex); a copy of `authEvent.pubkey` |
|
|
231
|
+
| `authEvent` | `SignetAuthEvent` | The verified, signed kind-21236 event: `id`, `pubkey`, `kind`, `created_at`, `tags`, `content`, `sig` |
|
|
232
|
+
| `credential` | `unknown` (optional) | Credential included in the response (Signet Login flows), passed through as received |
|
|
233
|
+
| `displayName` | `string` (optional) | Persona handle the user chose to share. Control and bidi characters are stripped and it is capped at 64 characters; still escape it when rendering |
|
|
234
|
+
| `bunkerUri` | `string` (optional) | A `bunker://` URI for upgrading to a live signer. Absent on auth-only flows |
|
|
235
|
+
| `createdAt` | `number` | Unix seconds at which the auth event was signed |
|
|
236
|
+
|
|
237
|
+
**Constants:** `AUTH_FRESHNESS_WINDOW_SEC` (`300`, seconds) and `DEFAULT_RELAY_URL` (`'wss://nos.lol'`).
|
|
238
|
+
|
|
170
239
|
## Age Range Values
|
|
171
240
|
|
|
172
241
|
| Value | Meaning |
|
|
@@ -177,11 +246,12 @@ Returns `Promise<SignetVerifyResult>`
|
|
|
177
246
|
| `'13-17'` | Ages 13–17 |
|
|
178
247
|
| `'18+'` | Adult (18 and over) |
|
|
179
248
|
|
|
249
|
+
Matching is exact: the credential's age range must equal `requiredAgeRange`. An `'18+'` credential does not satisfy `'13-17'`, and a `'13-17'` credential does not satisfy `'18+'`. Any other `requiredAgeRange` is rejected: `verifyAge` resolves at once with `error: 'invalid-age-range'` and shows no modal.
|
|
250
|
+
|
|
180
251
|
## Privacy
|
|
181
252
|
|
|
182
253
|
- No personal data is transmitted — only a cryptographic proof of age range
|
|
183
254
|
- No account creation required on the website
|
|
184
255
|
- No cookies beyond session management
|
|
185
|
-
-
|
|
186
|
-
-
|
|
187
|
-
- Compliant with GDPR, COPPA, UK Online Safety Act, France SREN law
|
|
256
|
+
- Proof verification runs in the browser. `verifyAge` makes one network request, to the verification bot, unless `verifierCheckUrl` is `null`; it opens no relay connection, and the proof reaches the modal over a same-origin `BroadcastChannel`, not the network. `waitForAuthResponse` connects only to the relay you give it
|
|
257
|
+
- The verifier check is a single GET request that sends only the verifier's public key and returns confirmed or not
|
package/llms.txt
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
For websites that need to gate content by age range (adult content, age
|
|
9
9
|
brackets for minors) without running their own verification flow. A single
|
|
10
|
-
function call opens a
|
|
11
|
-
and checks both the credential and
|
|
12
|
-
registration.
|
|
10
|
+
function call opens a modal, waits for a signed response on a same-origin
|
|
11
|
+
`BroadcastChannel` (no relay connection), and checks both the credential and
|
|
12
|
+
the issuing verifier's professional registration.
|
|
13
13
|
|
|
14
14
|
## Getting Started
|
|
15
15
|
|
|
@@ -27,7 +27,8 @@ if (result.verified) {
|
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
For a script tag / CDN build, use the IIFE export (`signet-verify/iife`),
|
|
30
|
-
which exposes `window.Signet
|
|
30
|
+
which exposes `window.Signet`, for example
|
|
31
|
+
`https://cdn.jsdelivr.net/npm/signet-verify@0.7.1/dist/signet-verify.iife.js`.
|
|
31
32
|
|
|
32
33
|
## Key Concepts
|
|
33
34
|
|
|
@@ -38,10 +39,14 @@ which exposes `window.Signet`.
|
|
|
38
39
|
register (GMC, SRA, TRA, etc.) via a verification bot; this can be relaxed
|
|
39
40
|
with `acceptUnconfirmed` or pointed at a different bot with
|
|
40
41
|
`verifierCheckUrl`.
|
|
41
|
-
- **Same-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
- **Same-browser vs cross-device**: `verifyAge` covers the modal flow and
|
|
43
|
+
receives its response on a `BroadcastChannel` named
|
|
44
|
+
`signet-verify-<requestId>`; it makes one network request, to the
|
|
45
|
+
verification bot, and never connects to a relay (its `relayUrl` option is
|
|
46
|
+
only written into the request object). `waitForAuthResponse` is the
|
|
47
|
+
lower-level cross-device primitive for a consumer that mints its own
|
|
48
|
+
challenge and waits on a relay for the signed response; only it needs a
|
|
49
|
+
relay that serves kind-1059 gift wraps to an unauthenticated reader.
|
|
45
50
|
- **The sign-in deadline**: a cross-device wait has one deadline,
|
|
46
51
|
`issuedAt + AUTH_FRESHNESS_WINDOW_SEC`. `issuedAt` must be passed on every
|
|
47
52
|
call for the same sign-in, including retries after the page was
|
|
@@ -50,18 +55,26 @@ which exposes `window.Signet`.
|
|
|
50
55
|
## API Surface
|
|
51
56
|
|
|
52
57
|
- `verifyAge(requiredAgeRange, options?) => Promise<SignetVerifyResult>`:
|
|
53
|
-
the same-
|
|
58
|
+
the same-browser modal flow. `requiredAgeRange` must be one of
|
|
59
|
+
`'0-3'`, `'4-7'`, `'8-12'`, `'13-17'`, `'18+'` and is matched exactly.
|
|
60
|
+
Failures are reported in `result.error`, not as a rejection.
|
|
54
61
|
- `waitForAuthResponse(options) => Promise<SignetAuthResult>`: the
|
|
55
|
-
cross-device primitive
|
|
56
|
-
|
|
57
|
-
`
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
cross-device primitive. It resolves on success and rejects with an `Error`
|
|
63
|
+
whose `message` and `code` are the failure code (`expired`, `timeout`,
|
|
64
|
+
`denied`, `aborted`, `relay-refused`, and others listed in the README).
|
|
65
|
+
Options: `requestId`, `relayUrl`, `sessionPrivKey` (a 32-byte
|
|
66
|
+
`Uint8Array`) and `expectedOrigin` are required; `issuedAt` (unix
|
|
67
|
+
seconds), `timeout` (milliseconds), `since` (unix seconds) and
|
|
68
|
+
`abortSignal` are optional. The README has the full option and result
|
|
69
|
+
tables.
|
|
70
|
+
- `AUTH_FRESHNESS_WINDOW_SEC` (`300`, seconds), `DEFAULT_RELAY_URL`
|
|
71
|
+
(`'wss://nos.lol'`): constants used to compute and check the sign-in
|
|
72
|
+
deadline.
|
|
60
73
|
- Result and option types: `SignetVerifyResult`, `SignetVerifyOptions`,
|
|
61
74
|
`WaitForAuthOptions`, `SignetAuthResult`, `SignetAuthEvent`.
|
|
62
75
|
|
|
63
76
|
## Optional
|
|
64
77
|
|
|
65
78
|
- Full API reference, error codes and age range values: [README](README.md)
|
|
66
|
-
- Cross-device example: [examples/cross-device-login.html](examples/cross-device-login.html)
|
|
79
|
+
- Cross-device example: [examples/cross-device-login.html](https://github.com/forgesworn/signet-verify/blob/main/examples/cross-device-login.html)
|
|
67
80
|
- Release history: [CHANGELOG.md](CHANGELOG.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signet-verify",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Signet SDK — website age verification and cross-device Sign-in-with-Signet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/signet-verify.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
-
"llms.txt"
|
|
18
|
+
"llms.txt",
|
|
19
|
+
"CHANGELOG.md"
|
|
19
20
|
],
|
|
20
21
|
"homepage": "https://github.com/forgesworn/signet-verify#readme",
|
|
21
22
|
"keywords": [
|