@spfn/auth 0.3.0-beta.6 → 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.
@@ -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
- platform?: string;
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<{
@@ -1424,6 +1668,11 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
1424
1668
  * downstream permission/tenant code consumes one principal shape and never
1425
1669
  * branches on how it was authenticated.
1426
1670
  *
1671
+ * An app adds its own scheme with `registerAuthProfile` at boot. The dispatch
1672
+ * it joins is the one below, unchanged: a name nobody registered is still
1673
+ * refused, and profile credentials mixed with an Authorization header are
1674
+ * still refused before either path runs.
1675
+ *
1427
1676
  * The clientProofV1 verifier reuses the phase-1 admission pieces (header
1428
1677
  * shape, canonical body, proof-input assembly, ECDSA verification) with two
1429
1678
  * production substitutions: the key directory is `user_public_keys` via
@@ -1444,8 +1693,13 @@ interface AuthContext {
1444
1693
  keyId: string;
1445
1694
  role: string | null;
1446
1695
  locale: string;
1447
- /** How the principal was authenticated. Informational — downstream code never branches on it. */
1448
- scheme: 'bearer' | 'clientProofV1' | 'oneTimeToken';
1696
+ /**
1697
+ * How the principal was authenticated. Informational — downstream code
1698
+ * never branches on it. The union stays open for the profiles an app
1699
+ * registers itself: the built-in names keep their autocomplete, and a
1700
+ * registered profile names its own scheme without editing this file.
1701
+ */
1702
+ scheme: 'bearer' | 'clientProofV1' | 'oneTimeToken' | (string & {});
1449
1703
  }
1450
1704
  /** A profile's verifier: admits the request and returns the principal, or throws. */
1451
1705
  interface AuthProfileVerifier {
@@ -1492,6 +1746,49 @@ type AuthProfileOutcome = {
1492
1746
  * handed to the generic error handler is classified by its class name instead.
1493
1747
  */
1494
1748
  declare function runAuthProfile(c: Context): Promise<AuthProfileOutcome>;
1749
+ /**
1750
+ * Registers an app's own verifier under a profile name.
1751
+ *
1752
+ * Call it at boot, before the first request: the registry is a module-global
1753
+ * read on every dispatch, so a profile registered later is simply a profile
1754
+ * the requests before it did not have. There is no freeze and no
1755
+ * unregistration — an auth surface that can be rearranged at runtime is a
1756
+ * surface an app bug can rearrange.
1757
+ *
1758
+ * A duplicate name throws rather than replacing the verifier that holds it,
1759
+ * `clientProofV1` included. A silent override is how a second import order, or
1760
+ * a copied profile name, quietly swaps the code that decides who is admitted.
1761
+ *
1762
+ * The verifier must expose a callable `verify` — a value that cannot admit
1763
+ * anyone is refused at boot rather than becoming a registry entry the dispatch
1764
+ * reads as "no profile header", which is anonymous passage under
1765
+ * `optionalAuth` for a request that presented profile credentials.
1766
+ *
1767
+ * The verifier returns the same `AuthContext` the Bearer path sets and refuses
1768
+ * by throwing. A resolve that carries no `userId` is refused as a throw too —
1769
+ * "no user" is a refusal, never a principal. A throw is not caught here:
1770
+ * `runAuthProfile` answers the internal clientProofV1 contract refusal and
1771
+ * nothing else, so a verifier's own error reaches the app's generic error
1772
+ * handler exactly as the Bearer path's `UnauthorizedError` does — and never
1773
+ * becomes anonymous passage, not even under `optionalAuth`.
1774
+ *
1775
+ * @example
1776
+ * ```typescript
1777
+ * registerAuthProfile('serviceTokenV1', {
1778
+ * verify: async (c) =>
1779
+ * {
1780
+ * const user = await authenticateServiceToken(c.req.header('x-acme-service-token'));
1781
+ * if (user === null)
1782
+ * {
1783
+ * throw new UnauthorizedError({ message: 'Invalid service token' });
1784
+ * }
1785
+ *
1786
+ * return { user, userId: String(user.id), keyId: 'service', role: null, locale: 'en', scheme: 'serviceTokenV1' };
1787
+ * },
1788
+ * });
1789
+ * ```
1790
+ */
1791
+ declare function registerAuthProfile(profileId: string, verifier: AuthProfileVerifier): void;
1495
1792
 
1496
1793
  declare module 'hono' {
1497
1794
  interface ContextVariableMap {
@@ -1558,4 +1855,97 @@ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
1558
1855
  */
1559
1856
  declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
1560
1857
 
1561
- export { type SendVerificationCodeParams as $, type AuthInitOptions as A, type OAuthCodeExchangeOptions as B, type ConfirmSignupLinkResult as C, DeviceNameSchema as D, EmailSchema as E, type OAuthNativeParams as F, type OAuthStartParams as G, type OAuthTokens as H, type IssueOneTimeTokenResult as I, PasswordSchema as J, type KeySummary as K, type LoginResult as L, PhoneSchema as M, type NativeVerifyOptions as N, type OAuthStartResult as O, type PermissionConfig as P, PlatformSchema as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RegisterParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type RegisterPublicKeyParams as W, type RequestSignupLinkParams as X, type RevokeAllKeysParams as Y, type RevokeKeyParams as Z, type RotateKeyParams as _, type RegisterResult as a, TargetTypeSchema as a0, type UnlinkNotification as a1, UnlinkNotifyRejection as a2, type UnlinkNotifyRequest as a3, type UnlinkNotifyResult as a4, VerificationPurposeSchema as a5, type VerifyCodeParams as a6, type VerifyCodeResult as a7, authenticate as a8, buildOAuthErrorUrl as a9, rotateKeyService as aA, runAuthProfile as aB, selectAuthProfile as aC, sendVerificationCodeService as aD, verifyCodeService as aE, verifyOneTimeTokenService as aF, changePasswordService as aa, completeSignupService as ab, confirmSignupLinkService as ac, getEnabledOAuthProviders as ad, getGoogleAccessToken as ae, getOAuthProvider as af, getRegisteredProviders as ag, isOAuthProviderEnabled as ah, isSafeReturnPath as ai, issueOneTimeTokenService as aj, listKeysService as ak, loginService as al, logoutService as am, oauthCallbackService as an, oauthNativeService as ao, oauthStartService as ap, oauthUnlinkNotifyService as aq, optionalAuth as ar, registerOAuthProvider as as, registerPublicKeyService as at, registerService as au, requestSignupLinkService as av, requireEnabledProvider as aw, resolveAuthenticatedUser as ax, revokeAllKeysService as ay, revokeKeyService as az, type RequestSignupLinkResult as b, type RotateKeyResult as c, type RevokeAllKeysResult as d, type OAuthNativeResult as e, type ProfileInfo as f, type AuthSession as g, PERMISSION_CATEGORIES as h, type PermissionCategory as i, VERIFICATION_TARGET_TYPES as j, type VerificationPurpose as k, type VerificationTargetType as l, mainAuthRouter as m, type OAuthProvider as n, type AuthContext as o, type AuthProfileOutcome as p, type AuthProfileVerifier as q, type ChangePasswordParams as r, type CompleteSignupParams as s, type ConfirmSignupLinkParams as t, KEY_FINGERPRINT_PREFIX_LENGTH as u, type LoginParams as v, type LogoutParams as w, type NormalizedIdentity as x, type OAuthCallbackParams as y, type OAuthCallbackResult as z };
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 };