@spfn/auth 0.3.0-beta.7 → 0.3.0-beta.8
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 +378 -0
- package/dist/client-proof.d.ts +23 -12
- package/dist/client-proof.js +143 -4
- package/dist/client-proof.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +76 -3
- package/dist/errors.js +45 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +46 -6
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -1
- package/dist/{authenticate-Mg9D7Nys.d.ts → machine-principals-Bd5hp76H.d.ts} +343 -6
- package/dist/nextjs/api.js +190 -9
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.js +59 -8
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +719 -89
- package/dist/server.js +1383 -440
- package/dist/server.js.map +1 -1
- package/migrations/20260901091716_fine_arclight/migration.sql +21 -0
- package/migrations/20260901091716_fine_arclight/snapshot.json +3849 -0
- package/package.json +2 -2
|
@@ -169,6 +169,72 @@ declare const PhoneSchema: _sinclair_typebox.TString;
|
|
|
169
169
|
*/
|
|
170
170
|
declare const DeviceNameSchema: _sinclair_typebox.TString;
|
|
171
171
|
declare const PlatformSchema: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Key material as a device sends it, bounded.
|
|
174
|
+
*
|
|
175
|
+
* The bounds exist for the one route that takes this material from a caller who
|
|
176
|
+
* has not authenticated and cannot: `POST /_auth/device/start` persists what it
|
|
177
|
+
* is given, and a correctly fingerprinted megabyte of base64 would sit in
|
|
178
|
+
* `device_authorizations` until something swept it — and nothing sweeps it.
|
|
179
|
+
*
|
|
180
|
+
* The numbers are what real key material measures, with room to spare. The
|
|
181
|
+
* package's own generators produce SPKI DER in base64: 124 characters for
|
|
182
|
+
* ES256 (P-256), 392 for RS256 (RSA-2048). An RSA-4096 key would be 736, an
|
|
183
|
+
* RSA-8192 key about 1400, and the same 4096-bit key PEM-armoured about 800 —
|
|
184
|
+
* so 2048 admits every shape of key anyone could reasonably present, while a
|
|
185
|
+
* megabyte is refused three orders of magnitude before it reaches a row.
|
|
186
|
+
*
|
|
187
|
+
* `keyId` is a UUID (36) everywhere this package generates one; 64 leaves room
|
|
188
|
+
* for a client that prefixes or namespaces its own. `fingerprint` is SHA-256
|
|
189
|
+
* hex, exactly 64, and nothing else can ever verify against the public key —
|
|
190
|
+
* 128 is the length a longer digest would need, and no more.
|
|
191
|
+
*/
|
|
192
|
+
declare const PublicKeySchema: _sinclair_typebox.TString;
|
|
193
|
+
declare const KeyIdSchema: _sinclair_typebox.TString;
|
|
194
|
+
declare const FingerprintSchema: _sinclair_typebox.TString;
|
|
195
|
+
/**
|
|
196
|
+
* The code a person reads off the waiting device and types on their own.
|
|
197
|
+
*
|
|
198
|
+
* Loose on purpose: 8 characters plus an optional dash is what is shown, but the
|
|
199
|
+
* server folds whitespace, dashes and lower case away before looking anything up,
|
|
200
|
+
* so refusing those spellings here would refuse a code that is on screen. The
|
|
201
|
+
* bounds exist to stop an unbounded string reaching the database, not to spell
|
|
202
|
+
* out the format — `USER_CODE_ALPHABET` is the only thing that can match a row.
|
|
203
|
+
*/
|
|
204
|
+
declare const UserCodeSchema: _sinclair_typebox.TString;
|
|
205
|
+
/**
|
|
206
|
+
* What `POST /_auth/device/poll` answers with.
|
|
207
|
+
*
|
|
208
|
+
* A union, because the two answers are different kinds of thing rather than one
|
|
209
|
+
* shape with optional fields: pending says "ask again in this long", approved is
|
|
210
|
+
* a completed login carrying exactly what `/_auth/login` returns. `status` is the
|
|
211
|
+
* discriminant, so a generated client narrows on it instead of testing which
|
|
212
|
+
* fields happen to be present.
|
|
213
|
+
*
|
|
214
|
+
* The mobile contract has no union type, so it exports this as one object with
|
|
215
|
+
* `status` required and every branch field optional — see
|
|
216
|
+
* `deviceAuthorization.pollStatusRule` in the bundle. `intervalMillis` is an
|
|
217
|
+
* integer for the same reason: that grammar carries no floating-point scalar,
|
|
218
|
+
* and a count of milliseconds never needed one.
|
|
219
|
+
*
|
|
220
|
+
* That integer is a promise two things keep, because nothing validates a response
|
|
221
|
+
* against this schema on the way out. `configureDeviceAuth` refuses an interval
|
|
222
|
+
* that is not a whole number of milliseconds, so the only value this branch can
|
|
223
|
+
* carry is one; and `contract-export.test.ts` reads this schema to check the
|
|
224
|
+
* exported declaration, so writing `Type.Number` here fails the suite instead of
|
|
225
|
+
* publishing an integer the server does not send.
|
|
226
|
+
*/
|
|
227
|
+
declare const DeviceAuthPollResponseSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
|
|
228
|
+
status: _sinclair_typebox.TLiteral<"pending">;
|
|
229
|
+
intervalMillis: _sinclair_typebox.TInteger;
|
|
230
|
+
}>, _sinclair_typebox.TObject<{
|
|
231
|
+
status: _sinclair_typebox.TLiteral<"approved">;
|
|
232
|
+
userId: _sinclair_typebox.TString;
|
|
233
|
+
publicId: _sinclair_typebox.TString;
|
|
234
|
+
email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
235
|
+
phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
236
|
+
passwordChangeRequired: _sinclair_typebox.TBoolean;
|
|
237
|
+
}>]>;
|
|
172
238
|
declare const PasswordSchema: _sinclair_typebox.TString;
|
|
173
239
|
declare const TargetTypeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
|
|
174
240
|
type VerificationTargetType = Static<typeof TargetTypeSchema>;
|
|
@@ -301,6 +367,133 @@ interface CompleteSignupParams {
|
|
|
301
367
|
*/
|
|
302
368
|
declare function completeSignupService(params: CompleteSignupParams): Promise<RegisterResult>;
|
|
303
369
|
|
|
370
|
+
/**
|
|
371
|
+
* @spfn/auth - Device Auth Service
|
|
372
|
+
*
|
|
373
|
+
* Device-code login: a device with no key on file yet shows a short code, the
|
|
374
|
+
* account owner types that code on a device that is already signed in, and the
|
|
375
|
+
* waiting device's key is registered on approval.
|
|
376
|
+
*
|
|
377
|
+
* There is no token to hand over. Every request in this system is signed by the
|
|
378
|
+
* calling device's own key, so "logging a device in" means one thing — getting
|
|
379
|
+
* its public key into `user_public_keys` under the right account. That is what
|
|
380
|
+
* the poll does, and it is why the poll returns exactly what `loginService`
|
|
381
|
+
* returns: from the client's side the two ways in are indistinguishable.
|
|
382
|
+
*
|
|
383
|
+
* | state ↓ op → | info | approve | deny | poll |
|
|
384
|
+
* | --- | --- | --- | --- | --- |
|
|
385
|
+
* | pending | device details | → approved | → denied | pending |
|
|
386
|
+
* | approved | AlreadyHandled | AlreadyHandled | AlreadyHandled | key registered, → consumed |
|
|
387
|
+
* | denied | AlreadyHandled | AlreadyHandled | AlreadyHandled | Denied |
|
|
388
|
+
* | consumed | NotFound | NotFound | NotFound | NotFound |
|
|
389
|
+
* | expired | Expired | Expired | Expired | Expired |
|
|
390
|
+
* | unknown | NotFound | NotFound | NotFound | NotFound |
|
|
391
|
+
*
|
|
392
|
+
* A global revocation — revoke-all, a password change, a deletion request —
|
|
393
|
+
* refuses the account's live records too, as `denied`, so they land in that row
|
|
394
|
+
* of the table. See `denyAllActiveByUserId`; the three callers are the three
|
|
395
|
+
* places that revoke every key at once.
|
|
396
|
+
*/
|
|
397
|
+
|
|
398
|
+
interface StartDeviceAuthParams {
|
|
399
|
+
publicKey: string;
|
|
400
|
+
keyId: string;
|
|
401
|
+
fingerprint: string;
|
|
402
|
+
algorithm?: KeyAlgorithmType;
|
|
403
|
+
/** Device label shown to the approver. Display only — nothing is authorized by it. */
|
|
404
|
+
deviceName?: string;
|
|
405
|
+
platform?: KeyPlatformType;
|
|
406
|
+
}
|
|
407
|
+
interface StartDeviceAuthResult {
|
|
408
|
+
/** Returned once. The waiting device polls with it; the server stores only its hash. */
|
|
409
|
+
deviceCode: string;
|
|
410
|
+
/** `XXXX-XXXX`, for the waiting device's screen and nowhere else. */
|
|
411
|
+
userCode: string;
|
|
412
|
+
expiresAtMillis: number;
|
|
413
|
+
/** Milliseconds the waiting device should wait between polls. */
|
|
414
|
+
intervalMillis: number;
|
|
415
|
+
}
|
|
416
|
+
interface DeviceAuthInfoParams {
|
|
417
|
+
userCode: string;
|
|
418
|
+
}
|
|
419
|
+
/** What the approver is shown about the device asking to be let in. */
|
|
420
|
+
interface DeviceAuthInfoResult {
|
|
421
|
+
deviceName?: string;
|
|
422
|
+
/** One of `KEY_PLATFORM`, which is what the route accepts and the column stores. */
|
|
423
|
+
platform?: KeyPlatformType;
|
|
424
|
+
/** First bytes of the pending key's fingerprint, as the device list truncates it. */
|
|
425
|
+
fingerprintPrefix: string;
|
|
426
|
+
requestedAtMillis: number;
|
|
427
|
+
expiresAtMillis: number;
|
|
428
|
+
}
|
|
429
|
+
interface ApproveDeviceAuthParams {
|
|
430
|
+
userCode: string;
|
|
431
|
+
/** The approver, read from their session. Never from a request body. */
|
|
432
|
+
userId: number;
|
|
433
|
+
}
|
|
434
|
+
interface DenyDeviceAuthParams {
|
|
435
|
+
userCode: string;
|
|
436
|
+
}
|
|
437
|
+
interface PollDeviceAuthParams {
|
|
438
|
+
deviceCode: string;
|
|
439
|
+
}
|
|
440
|
+
/** Nobody has answered yet. Not an error — the waiting device waits. */
|
|
441
|
+
interface DeviceAuthPendingResult {
|
|
442
|
+
status: 'pending';
|
|
443
|
+
intervalMillis: number;
|
|
444
|
+
}
|
|
445
|
+
/** Approved and spent: the key is registered and this is the login it produced. */
|
|
446
|
+
type DeviceAuthApprovedResult = {
|
|
447
|
+
status: 'approved';
|
|
448
|
+
} & LoginResult;
|
|
449
|
+
type PollDeviceAuthResult = DeviceAuthPendingResult | DeviceAuthApprovedResult;
|
|
450
|
+
/**
|
|
451
|
+
* Park a new device's key and hand back the codes it needs.
|
|
452
|
+
*
|
|
453
|
+
* The caller is unauthenticated by definition — this is what a device does before
|
|
454
|
+
* it has any way to prove anything — so nothing here is attributed to an account.
|
|
455
|
+
* The record gains an owner only when someone approves it.
|
|
456
|
+
*/
|
|
457
|
+
declare function startDeviceAuthService(params: StartDeviceAuthParams): Promise<StartDeviceAuthResult>;
|
|
458
|
+
/**
|
|
459
|
+
* What the approver sees before deciding.
|
|
460
|
+
*
|
|
461
|
+
* This is the whole defence against being talked into approving someone else's
|
|
462
|
+
* device: the answer names the device that is waiting, so the person holding the
|
|
463
|
+
* phone can see that it is not theirs. An approval screen that showed only the
|
|
464
|
+
* code would be asking them to confirm a number they were just told.
|
|
465
|
+
*/
|
|
466
|
+
declare function getDeviceAuthInfoService(params: DeviceAuthInfoParams): Promise<DeviceAuthInfoResult>;
|
|
467
|
+
/**
|
|
468
|
+
* Bind the record to the approving account.
|
|
469
|
+
*
|
|
470
|
+
* The key is not registered here. The waiting device may never come back, and a
|
|
471
|
+
* key registered for a device that stopped listening is a signing credential
|
|
472
|
+
* nobody asked for — so approval records the decision and the poll acts on it.
|
|
473
|
+
*
|
|
474
|
+
* Answers with the same device description `info` returns, so a client that let
|
|
475
|
+
* a user approve without looking first can still show them what they just let
|
|
476
|
+
* in — which is the moment someone talked into approving an attacker's device
|
|
477
|
+
* has to notice and revoke it.
|
|
478
|
+
*/
|
|
479
|
+
declare function approveDeviceAuthService(params: ApproveDeviceAuthParams): Promise<DeviceAuthInfoResult>;
|
|
480
|
+
/**
|
|
481
|
+
* Refuse the record, so the waiting device is told no instead of timing out.
|
|
482
|
+
*
|
|
483
|
+
* Denying binds no user: the point of refusing is that the account owner wants
|
|
484
|
+
* nothing to do with the request.
|
|
485
|
+
*/
|
|
486
|
+
declare function denyDeviceAuthService(params: DenyDeviceAuthParams): Promise<void>;
|
|
487
|
+
/**
|
|
488
|
+
* The waiting device asking whether anyone has answered.
|
|
489
|
+
*
|
|
490
|
+
* Approved is the one branch with a side effect, and it is a one-shot: the record
|
|
491
|
+
* is spent by a conditional update that names `approved`, so of two polls that
|
|
492
|
+
* arrive together exactly one registers the key. The loser matches nothing and is
|
|
493
|
+
* answered as if the code were unknown — which by then it is.
|
|
494
|
+
*/
|
|
495
|
+
declare function pollDeviceAuthService(params: PollDeviceAuthParams): Promise<PollDeviceAuthResult>;
|
|
496
|
+
|
|
304
497
|
/**
|
|
305
498
|
* @spfn/auth - Key Service
|
|
306
499
|
*
|
|
@@ -353,7 +546,8 @@ interface RevokeAllKeysResult {
|
|
|
353
546
|
interface KeySummary {
|
|
354
547
|
keyId: string;
|
|
355
548
|
deviceName?: string;
|
|
356
|
-
|
|
549
|
+
/** One of `KEY_PLATFORM`, which is what the routes accept and the column stores. */
|
|
550
|
+
platform?: KeyPlatformType;
|
|
357
551
|
algorithm: KeyAlgorithmType;
|
|
358
552
|
/** First bytes of the fingerprint — enough to tell two entries apart. */
|
|
359
553
|
fingerprintPrefix: string;
|
|
@@ -427,6 +621,16 @@ declare function listKeysService(params: ListKeysParams): Promise<KeySummary[]>;
|
|
|
427
621
|
* does not also end the session making the request. Passing
|
|
428
622
|
* `includeCurrent: true` is the full sign-out, which until now was reachable
|
|
429
623
|
* only as a side effect of changing a password.
|
|
624
|
+
*
|
|
625
|
+
* Live device authorizations are refused as well, in both modes. A device
|
|
626
|
+
* waiting on an approved code has no key yet, so it is never the caller's own
|
|
627
|
+
* device and never the one being spared — but its next poll would register a
|
|
628
|
+
* brand-new active key, which would undo the revocation seconds after it ran.
|
|
629
|
+
* That is the whole point of the call: the user has decided nothing else is to
|
|
630
|
+
* stay signed in.
|
|
631
|
+
*
|
|
632
|
+
* `revokedCount` counts keys only, since that is the number the caller's screen
|
|
633
|
+
* means by "devices signed out"; a code nobody had collected was never a session.
|
|
430
634
|
*/
|
|
431
635
|
declare function revokeAllKeysService(params: RevokeAllKeysParams): Promise<RevokeAllKeysResult>;
|
|
432
636
|
|
|
@@ -945,6 +1149,46 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
945
1149
|
platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
|
|
946
1150
|
}>;
|
|
947
1151
|
}, LoginResult>;
|
|
1152
|
+
startDeviceAuth: _spfn_core_route.RouteDef<{
|
|
1153
|
+
body: _sinclair_typebox.TObject<{
|
|
1154
|
+
publicKey: _sinclair_typebox.TString;
|
|
1155
|
+
keyId: _sinclair_typebox.TString;
|
|
1156
|
+
fingerprint: _sinclair_typebox.TString;
|
|
1157
|
+
algorithm: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>>;
|
|
1158
|
+
deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
1159
|
+
platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
|
|
1160
|
+
}>;
|
|
1161
|
+
}, {}, StartDeviceAuthResult>;
|
|
1162
|
+
pollDeviceAuth: _spfn_core_route.RouteDef<{
|
|
1163
|
+
body: _sinclair_typebox.TObject<{
|
|
1164
|
+
deviceCode: _sinclair_typebox.TString;
|
|
1165
|
+
}>;
|
|
1166
|
+
}, {}, {
|
|
1167
|
+
status: "pending";
|
|
1168
|
+
intervalMillis: number;
|
|
1169
|
+
} | {
|
|
1170
|
+
email?: string | undefined;
|
|
1171
|
+
phone?: string | undefined;
|
|
1172
|
+
status: "approved";
|
|
1173
|
+
userId: string;
|
|
1174
|
+
publicId: string;
|
|
1175
|
+
passwordChangeRequired: boolean;
|
|
1176
|
+
}>;
|
|
1177
|
+
getDeviceAuthInfo: _spfn_core_route.RouteDef<{
|
|
1178
|
+
body: _sinclair_typebox.TObject<{
|
|
1179
|
+
userCode: _sinclair_typebox.TString;
|
|
1180
|
+
}>;
|
|
1181
|
+
}, {}, DeviceAuthInfoResult>;
|
|
1182
|
+
approveDeviceAuth: _spfn_core_route.RouteDef<{
|
|
1183
|
+
body: _sinclair_typebox.TObject<{
|
|
1184
|
+
userCode: _sinclair_typebox.TString;
|
|
1185
|
+
}>;
|
|
1186
|
+
}, {}, DeviceAuthInfoResult>;
|
|
1187
|
+
denyDeviceAuth: _spfn_core_route.RouteDef<{
|
|
1188
|
+
body: _sinclair_typebox.TObject<{
|
|
1189
|
+
userCode: _sinclair_typebox.TString;
|
|
1190
|
+
}>;
|
|
1191
|
+
}, {}, void>;
|
|
948
1192
|
logout: _spfn_core_route.RouteDef<{}, {}, void>;
|
|
949
1193
|
rotateKey: _spfn_core_route.RouteDef<{}, {
|
|
950
1194
|
body: _sinclair_typebox.TObject<{
|
|
@@ -993,7 +1237,7 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
993
1237
|
id: number;
|
|
994
1238
|
name: string;
|
|
995
1239
|
displayName: string;
|
|
996
|
-
category: "
|
|
1240
|
+
category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
|
|
997
1241
|
}[];
|
|
998
1242
|
userId: number;
|
|
999
1243
|
publicId: string;
|
|
@@ -1293,8 +1537,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1293
1537
|
}, {}, {
|
|
1294
1538
|
roles: {
|
|
1295
1539
|
description: string | null;
|
|
1296
|
-
id: number;
|
|
1297
1540
|
name: string;
|
|
1541
|
+
id: number;
|
|
1298
1542
|
displayName: string;
|
|
1299
1543
|
isBuiltin: boolean;
|
|
1300
1544
|
isSystem: boolean;
|
|
@@ -1315,8 +1559,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1315
1559
|
}, {}, {
|
|
1316
1560
|
role: {
|
|
1317
1561
|
description: string | null;
|
|
1318
|
-
id: number;
|
|
1319
1562
|
name: string;
|
|
1563
|
+
id: number;
|
|
1320
1564
|
displayName: string;
|
|
1321
1565
|
isBuiltin: boolean;
|
|
1322
1566
|
isSystem: boolean;
|
|
@@ -1339,8 +1583,8 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
|
|
|
1339
1583
|
}, {}, {
|
|
1340
1584
|
role: {
|
|
1341
1585
|
description: string | null;
|
|
1342
|
-
id: number;
|
|
1343
1586
|
name: string;
|
|
1587
|
+
id: number;
|
|
1344
1588
|
displayName: string;
|
|
1345
1589
|
isBuiltin: boolean;
|
|
1346
1590
|
isSystem: boolean;
|
|
@@ -1611,4 +1855,97 @@ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
|
|
|
1611
1855
|
*/
|
|
1612
1856
|
declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
|
|
1613
1857
|
|
|
1614
|
-
|
|
1858
|
+
/** What a verified machine request acts as. Not a user, by construction. */
|
|
1859
|
+
interface MachinePrincipal {
|
|
1860
|
+
/** e.g. 'account' | 'service' | registrant-defined */
|
|
1861
|
+
subjectType: string;
|
|
1862
|
+
subjectId: string;
|
|
1863
|
+
scopes: string[];
|
|
1864
|
+
/** verifier-defined extras (claims, token id for audit, …) */
|
|
1865
|
+
claims?: Record<string, unknown>;
|
|
1866
|
+
/** which registered verifier admitted it */
|
|
1867
|
+
scheme: string;
|
|
1868
|
+
}
|
|
1869
|
+
interface MachineVerifierRegistration {
|
|
1870
|
+
/** unique id; becomes MachinePrincipal.scheme */
|
|
1871
|
+
id: string;
|
|
1872
|
+
/** exactly one discriminator */
|
|
1873
|
+
match: {
|
|
1874
|
+
tokenPrefix: string;
|
|
1875
|
+
} | {
|
|
1876
|
+
kidPrefix: string;
|
|
1877
|
+
};
|
|
1878
|
+
verify(token: string, c: Context): Promise<MachinePrincipal>;
|
|
1879
|
+
}
|
|
1880
|
+
declare module 'hono' {
|
|
1881
|
+
interface ContextVariableMap {
|
|
1882
|
+
machinePrincipal: MachinePrincipal;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
/** Read the verified machine principal a handler runs under. */
|
|
1886
|
+
declare function getMachinePrincipal(c: Context): MachinePrincipal | null;
|
|
1887
|
+
/**
|
|
1888
|
+
* Registers a verifier for one machine credential namespace. Call it at boot.
|
|
1889
|
+
*
|
|
1890
|
+
* Refused at registration: a duplicate `id`, a `match` that does not name
|
|
1891
|
+
* exactly one non-empty discriminator, a verifier without a callable `verify`,
|
|
1892
|
+
* and — the point of the check — a discriminator that shadows or is shadowed by
|
|
1893
|
+
* an already-registered one of the same kind. Two verifiers a token could match
|
|
1894
|
+
* would make admission depend on registration order; that is a boot-time bug,
|
|
1895
|
+
* not something the dispatch should resolve on every request.
|
|
1896
|
+
*
|
|
1897
|
+
* @example
|
|
1898
|
+
* ```typescript
|
|
1899
|
+
* registerMachineVerifier({
|
|
1900
|
+
* id: 'runtimeJwsV1',
|
|
1901
|
+
* match: { kidPrefix: 'machine:runtime:' },
|
|
1902
|
+
* verify: async (token) =>
|
|
1903
|
+
* {
|
|
1904
|
+
* const { payload } = await jwtVerify(token, RUNTIME_JWKS);
|
|
1905
|
+
*
|
|
1906
|
+
* return {
|
|
1907
|
+
* subjectType: 'account',
|
|
1908
|
+
* subjectId: String(payload.sub),
|
|
1909
|
+
* scopes: String(payload.scope ?? '').split(' ').filter(Boolean),
|
|
1910
|
+
* scheme: 'runtimeJwsV1',
|
|
1911
|
+
* };
|
|
1912
|
+
* },
|
|
1913
|
+
* });
|
|
1914
|
+
* ```
|
|
1915
|
+
*/
|
|
1916
|
+
declare function registerMachineVerifier(reg: MachineVerifierRegistration): void;
|
|
1917
|
+
/**
|
|
1918
|
+
* Admits a machine credential, or refuses. Sets `machinePrincipal`; `auth`
|
|
1919
|
+
* stays unset, so `getAuth(c)` is as empty here as on an anonymous request.
|
|
1920
|
+
*
|
|
1921
|
+
* Auto-skips the global 'auth' middleware, like `opsTokenAuth`.
|
|
1922
|
+
*
|
|
1923
|
+
* @example
|
|
1924
|
+
* ```typescript
|
|
1925
|
+
* export const ingest = route.post('/v1/ingest')
|
|
1926
|
+
* .use([machineAuth, requireMachineScope('events:write')])
|
|
1927
|
+
* .handler(async (c) => {
|
|
1928
|
+
* const { subjectType, subjectId } = getMachinePrincipal(c.raw)!;
|
|
1929
|
+
* // ...
|
|
1930
|
+
* });
|
|
1931
|
+
* ```
|
|
1932
|
+
*/
|
|
1933
|
+
declare const machineAuth: _spfn_core_route.NamedMiddleware<"machineAuth">;
|
|
1934
|
+
/**
|
|
1935
|
+
* Require the verified machine principal to carry every named scope.
|
|
1936
|
+
*
|
|
1937
|
+
* Fails closed: no principal in the context is a 401, not a pass — a route that
|
|
1938
|
+
* mounted this without `machineAuth` refuses rather than running unauthenticated,
|
|
1939
|
+
* exactly as `requireOpsScope` does. Scopes match exactly; there is no wildcard,
|
|
1940
|
+
* because what a scope string means belongs to the verifier that issued it.
|
|
1941
|
+
*
|
|
1942
|
+
* @example
|
|
1943
|
+
* ```ts
|
|
1944
|
+
* export const ingest = route.post('/v1/ingest')
|
|
1945
|
+
* .use([machineAuth, requireMachineScope('events:write')])
|
|
1946
|
+
* .handler(async () => { ... });
|
|
1947
|
+
* ```
|
|
1948
|
+
*/
|
|
1949
|
+
declare const requireMachineScope: _spfn_core_route.NamedMiddlewareFactory<"machineScope", string[]>;
|
|
1950
|
+
|
|
1951
|
+
export { type OAuthNativeParams as $, type AuthInitOptions as A, DeviceAuthPollResponseSchema as B, type ConfirmSignupLinkResult as C, type DeviceAuthInfoResult as D, DeviceNameSchema as E, EmailSchema as F, FingerprintSchema as G, KEY_FINGERPRINT_PREFIX_LENGTH as H, type IssueOneTimeTokenResult as I, KeyIdSchema as J, type KeySummary as K, type LoginResult as L, type LoginParams as M, type LogoutParams as N, type OAuthStartResult as O, type PermissionConfig as P, type MachinePrincipal as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type MachineVerifierRegistration as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type NativeVerifyOptions as W, type NormalizedIdentity as X, type OAuthCallbackParams as Y, type OAuthCallbackResult as Z, type OAuthCodeExchangeOptions as _, type RegisterResult as a, runAuthProfile as a$, type OAuthStartParams as a0, type OAuthTokens as a1, PasswordSchema as a2, PhoneSchema as a3, PlatformSchema as a4, type PollDeviceAuthParams as a5, type PollDeviceAuthResult as a6, PublicKeySchema as a7, type RegisterParams as a8, type RegisterPublicKeyParams as a9, getOAuthProvider as aA, getRegisteredProviders as aB, isOAuthProviderEnabled as aC, isSafeReturnPath as aD, issueOneTimeTokenService as aE, listKeysService as aF, loginService as aG, logoutService as aH, machineAuth as aI, oauthCallbackService as aJ, oauthNativeService as aK, oauthStartService as aL, oauthUnlinkNotifyService as aM, optionalAuth as aN, pollDeviceAuthService as aO, registerAuthProfile as aP, registerMachineVerifier as aQ, registerOAuthProvider as aR, registerPublicKeyService as aS, registerService as aT, requestSignupLinkService as aU, requireEnabledProvider as aV, requireMachineScope as aW, resolveAuthenticatedUser as aX, revokeAllKeysService as aY, revokeKeyService as aZ, rotateKeyService as a_, type RequestSignupLinkParams as aa, type RevokeAllKeysParams as ab, type RevokeKeyParams as ac, type RotateKeyParams as ad, type SendVerificationCodeParams as ae, type StartDeviceAuthParams as af, TargetTypeSchema as ag, type UnlinkNotification as ah, UnlinkNotifyRejection as ai, type UnlinkNotifyRequest as aj, type UnlinkNotifyResult as ak, UserCodeSchema as al, VerificationPurposeSchema as am, type VerifyCodeParams as an, type VerifyCodeResult as ao, approveDeviceAuthService as ap, authenticate as aq, buildOAuthErrorUrl as ar, changePasswordService as as, completeSignupService as at, confirmSignupLinkService as au, denyDeviceAuthService as av, getDeviceAuthInfoService as aw, getEnabledOAuthProviders as ax, getGoogleAccessToken as ay, getMachinePrincipal as az, type RequestSignupLinkResult as b, selectAuthProfile as b0, sendVerificationCodeService as b1, startDeviceAuthService as b2, verifyCodeService as b3, verifyOneTimeTokenService as b4, type StartDeviceAuthResult as c, type RotateKeyResult as d, type RevokeAllKeysResult as e, type OAuthNativeResult as f, type ProfileInfo as g, type AuthSession as h, PERMISSION_CATEGORIES as i, type PermissionCategory as j, VERIFICATION_TARGET_TYPES as k, type VerificationPurpose as l, mainAuthRouter as m, type VerificationTargetType as n, type OAuthProvider as o, type AuthContext as p, type ApproveDeviceAuthParams as q, type AuthProfileOutcome as r, type AuthProfileVerifier as s, type ChangePasswordParams as t, type CompleteSignupParams as u, type ConfirmSignupLinkParams as v, type DenyDeviceAuthParams as w, type DeviceAuthApprovedResult as x, type DeviceAuthInfoParams as y, type DeviceAuthPendingResult as z };
|