@human-gateway/sdk 0.0.1 → 0.1.0-alpha.1
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/README.md +698 -8
- package/dist/chunk-GJKDROWD.js +2 -0
- package/dist/chunk-GJKDROWD.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/server.cjs +2 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +15 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/types-BR0Sarec.d.cts +85 -0
- package/dist/types-BR0Sarec.d.ts +85 -0
- package/package.json +46 -16
- package/index.js +0 -5
package/README.md
CHANGED
|
@@ -1,21 +1,711 @@
|
|
|
1
1
|
# Human Gateway SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Human Gateway SDK lets partners add privacy-first human verification and human authentication to their apps without handling identity, biometrics, World ID internals, nullifiers, or proof verification logic.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Human Gateway is designed around two identifiers:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```txt
|
|
8
|
+
projectId -> identifies your Human Gateway project
|
|
9
|
+
actionKey -> identifies the specific verify/auth flow inside that project
|
|
10
|
+
```
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
For production integrations, pass an `actionKey` explicitly.
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
---
|
|
12
15
|
|
|
13
|
-
##
|
|
16
|
+
## Installation
|
|
14
17
|
|
|
15
18
|
```bash
|
|
16
19
|
npm install @human-gateway/sdk
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
> The SDK is currently in alpha. Package publication should be handled as a controlled release step. For local development, use the package from the Human Gateway monorepo.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quickstart: Verify a human
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { HumanGateway } from "@human-gateway/sdk";
|
|
30
|
+
|
|
31
|
+
const hg = new HumanGateway({
|
|
32
|
+
projectId: "project_xxx",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const result = await hg.verify({
|
|
36
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (result.verified_human) {
|
|
40
|
+
// Hide verify button
|
|
41
|
+
// Show verified badge
|
|
42
|
+
// Optionally wait for the signed backend callback before persisting state
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Example verification result:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"success": true,
|
|
51
|
+
"verified_human": true,
|
|
52
|
+
"verification_level": "orb",
|
|
53
|
+
"unique_for_partner": true,
|
|
54
|
+
"already_verified": false,
|
|
55
|
+
"project_id": "project_xxx"
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quickstart: Sign in a verified human
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { HumanGateway } from "@human-gateway/sdk";
|
|
65
|
+
|
|
66
|
+
const hg = new HumanGateway({
|
|
67
|
+
projectId: "project_xxx",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const result = await hg.auth({
|
|
71
|
+
actionKey: "hg_auth_action_key_xxx",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (result.success && result.verified_human) {
|
|
75
|
+
// Update your UI
|
|
76
|
+
// Store the returned partner-scoped session only according to your own app flow
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Example auth result:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"success": true,
|
|
85
|
+
"event": "auth.completed",
|
|
86
|
+
"verified_human": true,
|
|
87
|
+
"verification_level": "orb",
|
|
88
|
+
"partner_user_id": "partner_user_xxx",
|
|
89
|
+
"auth_session_id": "auth_session_xxx",
|
|
90
|
+
"project_id": "project_xxx",
|
|
91
|
+
"expires_at": "2026-06-25T00:00:00.000Z"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Project vs Action
|
|
98
|
+
|
|
99
|
+
A Human Gateway project represents one partner integration.
|
|
100
|
+
|
|
101
|
+
An action represents a specific flow inside that project.
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
|
|
105
|
+
```txt
|
|
106
|
+
Project: My SaaS App
|
|
107
|
+
|
|
108
|
+
Actions:
|
|
109
|
+
- Verify signup
|
|
110
|
+
- Auth login
|
|
111
|
+
- Verify voting
|
|
112
|
+
- Auth dashboard access
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use the same `projectId` for the project and pass the correct `actionKey` for the flow you want to run.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
await hg.verify({
|
|
119
|
+
actionKey: "hg_verify_signup_xxx",
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await hg.auth({
|
|
123
|
+
actionKey: "hg_auth_login_xxx",
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If `actionKey` is omitted, Human Gateway may use a fallback active action for compatibility. Explicit `actionKey` usage is recommended for production integrations.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## What Human Gateway does
|
|
132
|
+
|
|
133
|
+
Human Gateway verifies that a real human completed a World ID proof inside a specific project/action context.
|
|
134
|
+
|
|
135
|
+
Human Gateway does **not** expose:
|
|
136
|
+
|
|
137
|
+
* personal identity
|
|
138
|
+
* emails
|
|
139
|
+
* names
|
|
140
|
+
* biometrics
|
|
141
|
+
* World ID nullifiers
|
|
142
|
+
* raw World ID proof data
|
|
143
|
+
* internal Human Gateway user records
|
|
144
|
+
|
|
145
|
+
The partner receives only scoped results needed to update product behavior.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Frontend options
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const result = await hg.verify({
|
|
153
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
154
|
+
onOpen: () => {
|
|
155
|
+
console.log("Verification popup opened");
|
|
156
|
+
},
|
|
157
|
+
onSuccess: (result) => {
|
|
158
|
+
console.log("Verification completed:", result);
|
|
159
|
+
},
|
|
160
|
+
onError: (error) => {
|
|
161
|
+
console.error("Verification failed:", error.code);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const result = await hg.auth({
|
|
168
|
+
actionKey: "hg_auth_action_key_xxx",
|
|
169
|
+
onOpen: () => {
|
|
170
|
+
console.log("Auth popup opened");
|
|
171
|
+
},
|
|
172
|
+
onSuccess: (result) => {
|
|
173
|
+
console.log("Auth completed:", result);
|
|
174
|
+
},
|
|
175
|
+
onError: (error) => {
|
|
176
|
+
console.error("Auth failed:", error.code);
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## SDK configuration
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const hg = new HumanGateway({
|
|
187
|
+
projectId: "project_xxx",
|
|
188
|
+
environment: "production",
|
|
189
|
+
mode: "auto",
|
|
190
|
+
timeoutMs: 300000,
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Available options:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
type HumanGatewayOptions = {
|
|
198
|
+
projectId: string;
|
|
199
|
+
environment?: "production" | "sandbox";
|
|
200
|
+
mode?: "auto" | "popup" | "modal" | "redirect";
|
|
201
|
+
baseUrl?: string;
|
|
202
|
+
timeoutMs?: number;
|
|
203
|
+
};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`environment` identifies the intended Human Gateway project environment.
|
|
207
|
+
|
|
208
|
+
```txt
|
|
209
|
+
production -> production project/action configuration
|
|
210
|
+
sandbox -> sandbox project/action configuration
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Both `production` and `sandbox` currently use the hosted Human Gateway domain by default:
|
|
214
|
+
|
|
215
|
+
```txt
|
|
216
|
+
https://humangateway.dev
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
For local development, pass `baseUrl` explicitly.
|
|
220
|
+
|
|
221
|
+
Alpha behavior:
|
|
222
|
+
|
|
223
|
+
* `popup` is supported.
|
|
224
|
+
* `auto` currently uses popup behavior.
|
|
225
|
+
* `modal` is planned.
|
|
226
|
+
* `redirect` is planned.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Verify options
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
type HumanGatewayVerifyOptions = {
|
|
234
|
+
actionKey?: string;
|
|
235
|
+
onOpen?: () => void;
|
|
236
|
+
onClose?: () => void;
|
|
237
|
+
onSuccess?: (result: HumanGatewayResult) => void;
|
|
238
|
+
onError?: (error: HumanGatewayError) => void;
|
|
239
|
+
};
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Verify result:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
type HumanGatewayResult = {
|
|
246
|
+
success: boolean;
|
|
247
|
+
verified_human: boolean;
|
|
248
|
+
verification_level: "device" | "document" | "secure_document" | "orb" | null;
|
|
249
|
+
unique_for_partner: boolean;
|
|
250
|
+
already_verified: boolean;
|
|
251
|
+
project_id: string;
|
|
252
|
+
};
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Auth options
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
type HumanGatewayAuthOptions = {
|
|
261
|
+
actionKey?: string;
|
|
262
|
+
onOpen?: () => void;
|
|
263
|
+
onClose?: () => void;
|
|
264
|
+
onSuccess?: (result: HumanGatewayAuthResult) => void;
|
|
265
|
+
onError?: (error: HumanGatewayError) => void;
|
|
266
|
+
};
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Auth result:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
type HumanGatewayAuthResult = {
|
|
273
|
+
success: boolean;
|
|
274
|
+
event?: "auth.completed";
|
|
275
|
+
verified_human: boolean;
|
|
276
|
+
verification_level: "device" | "document" | "secure_document" | "orb" | null;
|
|
277
|
+
partner_user_id: string;
|
|
278
|
+
auth_session_id: string;
|
|
279
|
+
project_id: string;
|
|
280
|
+
expires_at: string;
|
|
281
|
+
};
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Popup behavior
|
|
287
|
+
|
|
288
|
+
The SDK opens a Human Gateway hosted flow in a centered browser popup.
|
|
289
|
+
|
|
290
|
+
This is expected behavior:
|
|
291
|
+
|
|
292
|
+
* The popup may show the browser address bar.
|
|
293
|
+
* The popup may be resizable or maximizable depending on the browser.
|
|
294
|
+
* The popup attempts to close itself after a successful flow.
|
|
295
|
+
* Some browsers may prevent programmatic closing; in that case, the user can close it manually.
|
|
296
|
+
|
|
297
|
+
The visible address bar is intentional and useful: it lets users confirm they are interacting with a legitimate Human Gateway domain.
|
|
298
|
+
|
|
299
|
+
### User gesture requirement
|
|
300
|
+
|
|
301
|
+
Call `hg.verify()` or `hg.auth()` directly from a user action such as a button click.
|
|
302
|
+
|
|
303
|
+
Modern browsers may block popups if they are opened after a long asynchronous operation, delayed promise, timer, or background task. For the best success rate, start the Human Gateway flow immediately inside the user interaction handler.
|
|
304
|
+
|
|
305
|
+
Recommended:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
button.addEventListener("click", async () => {
|
|
309
|
+
const result = await hg.verify({
|
|
310
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
console.log(result);
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Avoid delaying the popup:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
button.addEventListener("click", async () => {
|
|
321
|
+
await doLongAsyncWork();
|
|
322
|
+
|
|
323
|
+
const result = await hg.verify({
|
|
324
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
console.log(result);
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Allowed origin vs callback URL
|
|
334
|
+
|
|
335
|
+
Human Gateway uses two different URLs during an integration:
|
|
336
|
+
|
|
337
|
+
```txt
|
|
338
|
+
Allowed origin -> frontend origin that can launch hosted Human Gateway flows
|
|
339
|
+
Callback URL -> backend endpoint that receives signed POST callbacks
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Examples:
|
|
343
|
+
|
|
344
|
+
```txt
|
|
345
|
+
Allowed origin: https://yourapp.com
|
|
346
|
+
Callback URL: https://yourapp.com/api/hg/callback
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Do not configure only your domain as the callback URL:
|
|
350
|
+
|
|
351
|
+
```txt
|
|
352
|
+
Incorrect callback URL: https://yourapp.com
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Human Gateway sends `POST` requests to the exact callback URL configured in Partner Console. The callback URL must include the full backend endpoint path. Partners can choose their own backend route, for example:
|
|
356
|
+
|
|
357
|
+
```txt
|
|
358
|
+
https://yourapp.com/api/hg/callback
|
|
359
|
+
https://yourapp.com/api/webhooks/human-gateway
|
|
360
|
+
https://yourapp.com/webhooks/hg
|
|
361
|
+
https://yourapp.com/api/world/hg
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
The allowed origin is used by the frontend SDK and hosted flows. The callback URL is used by Human Gateway server-to-server delivery.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Frontend result vs backend callback
|
|
369
|
+
|
|
370
|
+
The frontend SDK result is useful for immediate UI updates.
|
|
371
|
+
|
|
372
|
+
The signed backend callback should be treated as the durable source of truth.
|
|
373
|
+
|
|
374
|
+
```txt
|
|
375
|
+
Frontend result -> update UI
|
|
376
|
+
Signed callback -> persist verified/auth state in partner backend
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
A malicious user can manipulate frontend state. They cannot forge a valid Human Gateway callback without the callback secret.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Backend callback verification
|
|
384
|
+
|
|
385
|
+
Human Gateway sends signed callbacks to the partner backend.
|
|
386
|
+
|
|
387
|
+
Configure the callback URL in Partner Console as the full backend endpoint path, for example:
|
|
388
|
+
|
|
389
|
+
```txt
|
|
390
|
+
https://yourapp.com/api/hg/callback
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Do not configure only `https://yourapp.com`; Human Gateway will send the callback to the exact URL you enter.
|
|
394
|
+
|
|
395
|
+
Server-side helpers are exported from `@human-gateway/sdk/server`.
|
|
396
|
+
|
|
397
|
+
You do not need to create a `HumanGateway` instance on your backend. The server helpers are pure functions designed to validate callback requests using the raw request body, signed headers, and your project callback secret.
|
|
398
|
+
|
|
399
|
+
Callback headers:
|
|
400
|
+
|
|
401
|
+
```txt
|
|
402
|
+
x-hg-event-id
|
|
403
|
+
x-hg-event
|
|
404
|
+
x-hg-project-id
|
|
405
|
+
x-hg-timestamp
|
|
406
|
+
x-hg-signature
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Example callback payload:
|
|
410
|
+
|
|
411
|
+
```json
|
|
412
|
+
{
|
|
413
|
+
"event_id": "callback_event_xxx",
|
|
414
|
+
"event": "verification.completed",
|
|
415
|
+
"success": true,
|
|
416
|
+
"verified_human": true,
|
|
417
|
+
"verification_level": "orb",
|
|
418
|
+
"unique_for_partner": false,
|
|
419
|
+
"already_verified": true,
|
|
420
|
+
"project_id": "project_xxx",
|
|
421
|
+
"created_at": "2026-06-25T00:00:00.000Z"
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Recommended callback verification
|
|
428
|
+
|
|
429
|
+
Use `verifyCallback` when you want Human Gateway to validate the signature, timestamp, required headers, JSON payload, event id, event type, and project id consistency.
|
|
430
|
+
|
|
431
|
+
```ts
|
|
432
|
+
import { verifyCallback } from "@human-gateway/sdk/server";
|
|
433
|
+
|
|
434
|
+
export async function POST(request: Request) {
|
|
435
|
+
const body = await request.text();
|
|
436
|
+
|
|
437
|
+
try {
|
|
438
|
+
const callback = verifyCallback({
|
|
439
|
+
body,
|
|
440
|
+
headers: request.headers,
|
|
441
|
+
// Use the callback secret configured for this project in Partner Console.
|
|
442
|
+
// You can generate or rotate it from the project callback settings.
|
|
443
|
+
secret: process.env.HG_CALLBACK_SECRET!,
|
|
444
|
+
expectedProjectId: "project_xxx",
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
if (callback.event === "verification.completed") {
|
|
448
|
+
const payload = callback.payload;
|
|
449
|
+
|
|
450
|
+
if (payload.verified_human === true) {
|
|
451
|
+
// Persist verified state in your backend
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (callback.event === "auth.completed") {
|
|
456
|
+
const payload = callback.payload;
|
|
457
|
+
|
|
458
|
+
if (payload.verified_human === true) {
|
|
459
|
+
// Persist or reconcile auth state in your backend
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return Response.json({ success: true });
|
|
464
|
+
} catch {
|
|
465
|
+
return new Response("Invalid Human Gateway callback", {
|
|
466
|
+
status: 401,
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Low-level signature verification
|
|
475
|
+
|
|
476
|
+
Use `verifyCallbackSignature` only if you want to verify the signature yourself and handle payload/header validation manually.
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
import { verifyCallbackSignature } from "@human-gateway/sdk/server";
|
|
480
|
+
|
|
481
|
+
export async function POST(request: Request) {
|
|
482
|
+
const rawBody = await request.text();
|
|
483
|
+
|
|
484
|
+
const isValid = verifyCallbackSignature({
|
|
485
|
+
rawBody,
|
|
486
|
+
timestamp: request.headers.get("x-hg-timestamp"),
|
|
487
|
+
signature: request.headers.get("x-hg-signature"),
|
|
488
|
+
// Use the callback secret configured for this project in Partner Console.
|
|
489
|
+
// You can generate or rotate it from the project callback settings.
|
|
490
|
+
secret: process.env.HG_CALLBACK_SECRET!,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
if (!isValid) {
|
|
494
|
+
return new Response("Invalid Human Gateway signature", {
|
|
495
|
+
status: 401,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const payload = JSON.parse(rawBody);
|
|
500
|
+
|
|
501
|
+
return Response.json({
|
|
502
|
+
success: true,
|
|
503
|
+
event: payload.event,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Callback verification errors
|
|
511
|
+
|
|
512
|
+
```ts
|
|
513
|
+
type HumanGatewayCallbackErrorCode =
|
|
514
|
+
| "callback_missing_body"
|
|
515
|
+
| "callback_missing_secret"
|
|
516
|
+
| "callback_missing_header"
|
|
517
|
+
| "callback_invalid_timestamp"
|
|
518
|
+
| "callback_expired_timestamp"
|
|
519
|
+
| "callback_invalid_signature_format"
|
|
520
|
+
| "callback_invalid_signature"
|
|
521
|
+
| "callback_invalid_json"
|
|
522
|
+
| "callback_invalid_payload"
|
|
523
|
+
| "callback_event_id_mismatch"
|
|
524
|
+
| "callback_event_type_mismatch"
|
|
525
|
+
| "callback_project_id_mismatch";
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Example:
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
import {
|
|
532
|
+
HumanGatewayCallbackError,
|
|
533
|
+
verifyCallback,
|
|
534
|
+
} from "@human-gateway/sdk/server";
|
|
535
|
+
|
|
536
|
+
try {
|
|
537
|
+
const callback = verifyCallback({
|
|
538
|
+
body,
|
|
539
|
+
headers,
|
|
540
|
+
secret: process.env.HG_CALLBACK_SECRET!,
|
|
541
|
+
});
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (error instanceof HumanGatewayCallbackError) {
|
|
544
|
+
console.error("Invalid Human Gateway callback:", error.code);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## SDK error codes
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
type HumanGatewayErrorCode =
|
|
555
|
+
| "popup_blocked"
|
|
556
|
+
| "user_closed"
|
|
557
|
+
| "timeout"
|
|
558
|
+
| "invalid_message"
|
|
559
|
+
| "invalid_origin"
|
|
560
|
+
| "verification_failed"
|
|
561
|
+
| "auth_failed"
|
|
562
|
+
| "unknown_error";
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Common handling:
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
import { HumanGateway, HumanGatewayError } from "@human-gateway/sdk";
|
|
569
|
+
|
|
570
|
+
const hg = new HumanGateway({
|
|
571
|
+
projectId: "project_xxx",
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
const result = await hg.verify({
|
|
576
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
577
|
+
});
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (error instanceof HumanGatewayError) {
|
|
580
|
+
if (error.code === "user_closed") {
|
|
581
|
+
// User cancelled the flow
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (error.code === "popup_blocked") {
|
|
585
|
+
// Ask the user to allow popups
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (error.code === "verification_failed") {
|
|
589
|
+
// The hosted verification flow did not complete successfully
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## Local development
|
|
598
|
+
|
|
599
|
+
```ts
|
|
600
|
+
const hg = new HumanGateway({
|
|
601
|
+
projectId: "project_1a7f21ff5e261645",
|
|
602
|
+
environment: "sandbox",
|
|
603
|
+
baseUrl: "http://localhost:3000",
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
await hg.verify({
|
|
607
|
+
actionKey: "hg_verify_action_key_xxx",
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
await hg.auth({
|
|
611
|
+
actionKey: "hg_auth_action_key_xxx",
|
|
612
|
+
});
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
`baseUrl` overrides the hosted Human Gateway domain. Use it for local testing, previews, or controlled internal validation.
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## Privacy-first guarantees
|
|
620
|
+
|
|
621
|
+
Human Gateway does not identify the user.
|
|
622
|
+
|
|
623
|
+
It verifies humanity inside a project/action context.
|
|
624
|
+
|
|
625
|
+
The partner may receive:
|
|
626
|
+
|
|
627
|
+
```txt
|
|
628
|
+
success
|
|
629
|
+
verified_human
|
|
630
|
+
verification_level
|
|
631
|
+
unique_for_partner
|
|
632
|
+
already_verified
|
|
633
|
+
partner_user_id
|
|
634
|
+
auth_session_id
|
|
635
|
+
project_id
|
|
636
|
+
expires_at
|
|
637
|
+
```
|
|
638
|
+
`verification_level` can be `device`, `document`, `secure_document`, `orb`, or `null`.
|
|
639
|
+
|
|
640
|
+
Human Gateway only returns the value provided by World ID. It does not infer, upgrade, or claim a stronger verification level.
|
|
641
|
+
|
|
642
|
+
The partner does not receive:
|
|
643
|
+
|
|
644
|
+
```txt
|
|
645
|
+
World ID nullifier
|
|
646
|
+
biometric data
|
|
647
|
+
personal identity
|
|
648
|
+
World proof internals
|
|
649
|
+
Human Gateway internal user object
|
|
650
|
+
raw World ID proof data
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## Recommended partner verification flow
|
|
656
|
+
|
|
657
|
+
```txt
|
|
658
|
+
1. User clicks "Verify with Human Gateway"
|
|
659
|
+
2. SDK opens Human Gateway popup
|
|
660
|
+
3. User completes World ID proof
|
|
661
|
+
4. Partner frontend receives UX result
|
|
662
|
+
5. Human Gateway sends signed callback to partner backend
|
|
663
|
+
6. Partner backend verifies callback
|
|
664
|
+
7. Partner persists verified status
|
|
665
|
+
8. Partner hides verification button
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## Recommended partner auth flow
|
|
671
|
+
|
|
672
|
+
```txt
|
|
673
|
+
1. User clicks "Sign in with Human Gateway"
|
|
674
|
+
2. SDK opens Human Gateway Auth popup
|
|
675
|
+
3. User completes World ID proof
|
|
676
|
+
4. Human Gateway creates a partner-scoped auth session
|
|
677
|
+
5. Partner frontend receives UX result
|
|
678
|
+
6. Human Gateway sends signed callback to partner backend
|
|
679
|
+
7. Partner backend verifies callback
|
|
680
|
+
8. Partner grants or reconciles app access according to its own session model
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Current alpha status
|
|
686
|
+
|
|
687
|
+
Implemented:
|
|
688
|
+
|
|
689
|
+
* popup verification flow
|
|
690
|
+
* popup auth flow
|
|
691
|
+
* action-specific `hg.verify({ actionKey })`
|
|
692
|
+
* action-specific `hg.auth({ actionKey })`
|
|
693
|
+
* fallback behavior without `actionKey`
|
|
694
|
+
* postMessage result delivery
|
|
695
|
+
* timeout handling
|
|
696
|
+
* user close detection
|
|
697
|
+
* duplicate verify/auth call prevention
|
|
698
|
+
* signed callback verification helper
|
|
699
|
+
* full callback validation helper
|
|
700
|
+
* ESM/CJS builds
|
|
701
|
+
* TypeScript types
|
|
702
|
+
* prepack build protection
|
|
703
|
+
* prepublish typecheck/build protection
|
|
704
|
+
|
|
705
|
+
Planned:
|
|
20
706
|
|
|
21
|
-
|
|
707
|
+
* iframe modal mode
|
|
708
|
+
* redirect fallback
|
|
709
|
+
* React helper
|
|
710
|
+
* expanded usage/session events
|
|
711
|
+
* public package release
|