@spfn/auth 0.2.1 → 0.3.0-beta.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.
Files changed (61) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1091 -2385
  3. package/dist/authenticate-55LeXHqZ.d.ts +1447 -0
  4. package/dist/client-proof.d.ts +606 -0
  5. package/dist/client-proof.js +1842 -0
  6. package/dist/client-proof.js.map +1 -0
  7. package/dist/config.d.ts +319 -3
  8. package/dist/config.js +155 -5
  9. package/dist/config.js.map +1 -1
  10. package/dist/crypto.d.ts +61 -0
  11. package/dist/crypto.js +108 -0
  12. package/dist/crypto.js.map +1 -0
  13. package/dist/errors.d.ts +180 -3
  14. package/dist/errors.js +116 -1
  15. package/dist/errors.js.map +1 -1
  16. package/dist/index.d.ts +166 -18
  17. package/dist/index.js +132 -8
  18. package/dist/index.js.map +1 -1
  19. package/dist/nextjs/api.js +404 -96
  20. package/dist/nextjs/api.js.map +1 -1
  21. package/dist/nextjs/server.d.ts +5 -4
  22. package/dist/nextjs/server.js +165 -26
  23. package/dist/nextjs/server.js.map +1 -1
  24. package/dist/server.d.ts +2356 -1053
  25. package/dist/server.js +5153 -736
  26. package/dist/server.js.map +1 -1
  27. package/dist/session-DTHahDQ9.d.ts +53 -0
  28. package/dist/types-DYyhze28.d.ts +98 -0
  29. package/dist/wire-version-CtzMKvBB.d.ts +134 -0
  30. package/migrations/20251125021229_premium_famine/snapshot.json +2641 -0
  31. package/migrations/20260225130050_smooth_the_fury/snapshot.json +2686 -0
  32. package/migrations/20260308141417_deep_iceman/snapshot.json +2686 -0
  33. package/migrations/20260308151309_perfect_deathbird/snapshot.json +2731 -0
  34. package/migrations/20260308201135_concerned_rawhide_kid/snapshot.json +2786 -0
  35. package/migrations/20260629103209_lethal_lifeguard/migration.sql +32 -0
  36. package/migrations/20260629103209_lethal_lifeguard/snapshot.json +2786 -0
  37. package/migrations/20260709073531_easy_hardball/migration.sql +24 -0
  38. package/migrations/20260709073531_easy_hardball/snapshot.json +3119 -0
  39. package/migrations/20260714081434_glossy_major_mapleleaf/migration.sql +1 -0
  40. package/migrations/20260714081434_glossy_major_mapleleaf/snapshot.json +3112 -0
  41. package/migrations/20260804105939_amazing_bushwacker/migration.sql +3 -0
  42. package/migrations/20260804105939_amazing_bushwacker/snapshot.json +3112 -0
  43. package/migrations/20260804110033_fat_piledriver/migration.sql +2 -0
  44. package/migrations/20260804110033_fat_piledriver/snapshot.json +3138 -0
  45. package/migrations/20260805143152_vengeful_ravenous/migration.sql +4 -0
  46. package/migrations/20260805143152_vengeful_ravenous/snapshot.json +3190 -0
  47. package/migrations/20260807145911_mixed_invisible_woman/migration.sql +11 -0
  48. package/migrations/20260807145911_mixed_invisible_woman/snapshot.json +3334 -0
  49. package/package.json +59 -40
  50. package/dist/authenticate-eucncHxN.d.ts +0 -940
  51. package/migrations/meta/0000_snapshot.json +0 -1632
  52. package/migrations/meta/0001_snapshot.json +0 -1660
  53. package/migrations/meta/0002_snapshot.json +0 -1660
  54. package/migrations/meta/0003_snapshot.json +0 -1689
  55. package/migrations/meta/0004_snapshot.json +0 -1721
  56. package/migrations/meta/_journal.json +0 -41
  57. /package/migrations/{0000_premium_famine.sql → 20251125021229_premium_famine/migration.sql} +0 -0
  58. /package/migrations/{0001_smooth_the_fury.sql → 20260225130050_smooth_the_fury/migration.sql} +0 -0
  59. /package/migrations/{0002_deep_iceman.sql → 20260308141417_deep_iceman/migration.sql} +0 -0
  60. /package/migrations/{0003_perfect_deathbird.sql → 20260308151309_perfect_deathbird/migration.sql} +0 -0
  61. /package/migrations/{0004_concerned_rawhide_kid.sql → 20260308201135_concerned_rawhide_kid/migration.sql} +0 -0
@@ -0,0 +1,1447 @@
1
+ import * as _spfn_core_route from '@spfn/core/route';
2
+ import { K as KeyAlgorithmType, h as KeyPlatformType, j as SocialProvider } from './types-DYyhze28.js';
3
+ import * as _sinclair_typebox from '@sinclair/typebox';
4
+ import { Static } from '@sinclair/typebox';
5
+ import { Context } from 'hono';
6
+ import { User } from '@spfn/auth/server';
7
+
8
+ /**
9
+ * Role information for client/API responses
10
+ */
11
+ interface Role {
12
+ id: number;
13
+ name: string;
14
+ displayName: string;
15
+ description: string | null;
16
+ isBuiltin: boolean;
17
+ isSystem: boolean;
18
+ isActive: boolean;
19
+ priority: number;
20
+ createdAt: Date;
21
+ updatedAt: Date;
22
+ }
23
+ /**
24
+ * Permission information for client/API responses
25
+ */
26
+ interface Permission {
27
+ id: number;
28
+ name: string;
29
+ displayName: string;
30
+ description: string | null;
31
+ category: string | null;
32
+ isBuiltin: boolean;
33
+ isSystem: boolean;
34
+ isActive: boolean;
35
+ metadata: Record<string, any> | null;
36
+ createdAt: Date;
37
+ updatedAt: Date;
38
+ }
39
+ interface AuthSession {
40
+ userId: number;
41
+ publicId: string;
42
+ email: string | null;
43
+ emailVerified: boolean;
44
+ phoneVerified: boolean;
45
+ hasPassword: boolean;
46
+ role: Role;
47
+ permissions: Permission[];
48
+ }
49
+ interface ProfileInfo {
50
+ profileId: number;
51
+ displayName: string | null;
52
+ firstName: string | null;
53
+ lastName: string | null;
54
+ avatarUrl: string | null;
55
+ bio: string | null;
56
+ locale: string;
57
+ timezone: string;
58
+ website: string | null;
59
+ location: string | null;
60
+ company: string | null;
61
+ jobTitle: string | null;
62
+ metadata: Record<string, any> | null;
63
+ createdAt: Date;
64
+ updatedAt: Date;
65
+ }
66
+ /**
67
+ * User Profile Response
68
+ *
69
+ * Complete user data including:
70
+ * - User fields at top level (userId, email, etc.)
71
+ * - Profile data as nested field (optional)
72
+ *
73
+ * Excludes:
74
+ * - Role and permissions (use auth session API)
75
+ */
76
+ interface UserProfile {
77
+ userId: number;
78
+ publicId: string;
79
+ email: string | null;
80
+ username: string | null;
81
+ emailVerified: boolean;
82
+ phoneVerified: boolean;
83
+ lastLoginAt: Date | null;
84
+ createdAt: Date;
85
+ updatedAt: Date;
86
+ profile: ProfileInfo | null;
87
+ }
88
+
89
+ /**
90
+ * @spfn/auth - Auth Service
91
+ *
92
+ * Core authentication logic: registration, login, logout, password management
93
+ */
94
+
95
+ interface RegisterParams {
96
+ email?: string;
97
+ phone?: string;
98
+ verificationToken: string;
99
+ password: string;
100
+ publicKey: string;
101
+ keyId: string;
102
+ fingerprint: string;
103
+ algorithm?: KeyAlgorithmType;
104
+ deviceName?: string;
105
+ platform?: KeyPlatformType;
106
+ metadata?: Record<string, unknown>;
107
+ }
108
+ interface RegisterResult {
109
+ userId: string;
110
+ publicId: string;
111
+ email?: string;
112
+ phone?: string;
113
+ }
114
+ interface LoginParams {
115
+ email?: string;
116
+ phone?: string;
117
+ password: string;
118
+ publicKey: string;
119
+ keyId: string;
120
+ fingerprint: string;
121
+ oldKeyId?: string;
122
+ algorithm?: KeyAlgorithmType;
123
+ deviceName?: string;
124
+ platform?: KeyPlatformType;
125
+ }
126
+ interface LoginResult {
127
+ userId: string;
128
+ publicId: string;
129
+ email?: string;
130
+ phone?: string;
131
+ passwordChangeRequired: boolean;
132
+ }
133
+ interface LogoutParams {
134
+ userId: number;
135
+ keyId: string;
136
+ }
137
+ interface ChangePasswordParams {
138
+ userId: number;
139
+ currentPassword?: string;
140
+ newPassword: string;
141
+ passwordHash?: string;
142
+ }
143
+ /**
144
+ * Register a new user account
145
+ */
146
+ declare function registerService(params: RegisterParams): Promise<RegisterResult>;
147
+ /**
148
+ * Authenticate user and create session
149
+ */
150
+ declare function loginService(params: LoginParams): Promise<LoginResult>;
151
+ /**
152
+ * Logout user (revoke current key)
153
+ */
154
+ declare function logoutService(params: LogoutParams): Promise<void>;
155
+ /**
156
+ * Change user password
157
+ */
158
+ declare function changePasswordService(params: ChangePasswordParams): Promise<void>;
159
+
160
+ declare const EmailSchema: _sinclair_typebox.TString;
161
+ declare const PhoneSchema: _sinclair_typebox.TString;
162
+ /**
163
+ * Optional device labels a client may send when registering a key.
164
+ *
165
+ * Display only: the key list uses them to tell one device from another, and
166
+ * nothing is authorized or refused by either value, so a client that lies about
167
+ * them gains nothing. Both are omitted by every key registered before they
168
+ * existed, hence optional rather than defaulted.
169
+ */
170
+ declare const DeviceNameSchema: _sinclair_typebox.TString;
171
+ declare const PlatformSchema: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>;
172
+ declare const PasswordSchema: _sinclair_typebox.TString;
173
+ declare const TargetTypeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
174
+ type VerificationTargetType = Static<typeof TargetTypeSchema>;
175
+ declare const VERIFICATION_TARGET_TYPES: readonly ["email", "phone"];
176
+ declare const VerificationPurposeSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">, _sinclair_typebox.TLiteral<"account_deletion">]>;
177
+ type VerificationPurpose = Static<typeof VerificationPurposeSchema>;
178
+ declare const VERIFICATION_PURPOSES: readonly ["registration", "login", "password_reset", "email_change", "phone_change", "account_deletion"];
179
+
180
+ /**
181
+ * @spfn/auth - Verification Service
182
+ *
183
+ * Handles OTP code generation, validation, and delivery
184
+ */
185
+
186
+ interface SendVerificationCodeParams {
187
+ target: string;
188
+ targetType: VerificationTargetType;
189
+ purpose: VerificationPurpose;
190
+ }
191
+ interface SendVerificationCodeResult {
192
+ success: boolean;
193
+ expiresAt: string;
194
+ }
195
+ interface VerifyCodeParams {
196
+ target: string;
197
+ targetType: VerificationTargetType;
198
+ code: string;
199
+ purpose: VerificationPurpose;
200
+ }
201
+ interface VerifyCodeResult {
202
+ valid: boolean;
203
+ verificationToken: string;
204
+ }
205
+ /**
206
+ * Send verification code via email or SMS
207
+ */
208
+ declare function sendVerificationCodeService(params: SendVerificationCodeParams): Promise<SendVerificationCodeResult>;
209
+ /**
210
+ * Verify OTP code and return verification token
211
+ */
212
+ declare function verifyCodeService(params: VerifyCodeParams): Promise<{
213
+ valid: boolean;
214
+ verificationToken: string;
215
+ }>;
216
+
217
+ /**
218
+ * @spfn/auth - Key Service
219
+ *
220
+ * Handles public key registration, rotation, and revocation
221
+ */
222
+
223
+ interface RegisterPublicKeyParams {
224
+ userId: number;
225
+ keyId: string;
226
+ publicKey: string;
227
+ fingerprint: string;
228
+ algorithm?: KeyAlgorithmType;
229
+ /** Device label for the key list. Display only — nothing is authorized by it. */
230
+ deviceName?: string;
231
+ platform?: KeyPlatformType;
232
+ }
233
+ interface RotateKeyParams {
234
+ userId: number;
235
+ oldKeyId: string;
236
+ newKeyId: string;
237
+ newPublicKey: string;
238
+ fingerprint: string;
239
+ algorithm?: KeyAlgorithmType;
240
+ /** Omitted: the replaced key's label carries over, so rotation keeps its name. */
241
+ deviceName?: string;
242
+ platform?: KeyPlatformType;
243
+ }
244
+ interface RotateKeyResult {
245
+ success: boolean;
246
+ keyId: string;
247
+ }
248
+ interface RevokeKeyParams {
249
+ userId: number;
250
+ keyId: string;
251
+ reason: string;
252
+ }
253
+ interface RevokeAllKeysParams {
254
+ userId: number;
255
+ /** The key the request itself is signed with — spared unless includeCurrent. */
256
+ currentKeyId: string;
257
+ /** true signs the caller out too. Default false: "my other devices". */
258
+ includeCurrent?: boolean;
259
+ reason: string;
260
+ }
261
+ interface RevokeAllKeysResult {
262
+ revokedCount: number;
263
+ currentKeyRevoked: boolean;
264
+ }
265
+ /** One registered device as the account surface shows it. */
266
+ interface KeySummary {
267
+ keyId: string;
268
+ deviceName?: string;
269
+ platform?: string;
270
+ algorithm: KeyAlgorithmType;
271
+ /** First bytes of the fingerprint — enough to tell two entries apart. */
272
+ fingerprintPrefix: string;
273
+ /**
274
+ * Milliseconds since the Unix epoch, not an ISO string.
275
+ *
276
+ * One representation of a moment across the whole surface: a generated Swift
277
+ * or Kotlin client reads an integer with no date formatter, and
278
+ * `ISO8601DateFormatter` rejecting fractional seconds by default stops being
279
+ * a way for the two SDKs to disagree about the same value.
280
+ */
281
+ createdAtMillis: number;
282
+ lastUsedAtMillis?: number;
283
+ expiresAtMillis?: number;
284
+ /** The TTL has run out. The key still reads as active; authenticate refuses it. */
285
+ isExpired: boolean;
286
+ /** False once revoked. Only ever false when the caller asked for revoked keys. */
287
+ isActive: boolean;
288
+ /** When it was revoked, for the "what did I cut off, and when" reading. */
289
+ revokedAtMillis?: number;
290
+ }
291
+ interface ListKeysParams {
292
+ userId: number;
293
+ /** Also return keys already revoked. Default false: only what can still sign. */
294
+ includeRevoked?: boolean;
295
+ }
296
+ /** How much of the fingerprint the list returns. */
297
+ declare const KEY_FINGERPRINT_PREFIX_LENGTH = 8;
298
+ /**
299
+ * Register a new public key for a user
300
+ *
301
+ * `keyId` is UNIQUE across all users, so the lookup must ignore `isActive` —
302
+ * filtering on it misses a revoked row and the insert then fails on the unique
303
+ * index, rolling the whole login transaction back into a 500. Reuse is refused
304
+ * with a domain error instead, telling the client to generate a fresh keyId.
305
+ *
306
+ * @throws KeyIdAlreadyRegisteredError keyId가 이미 쓰인 값일 때 (자기 폐기 키 재사용 · 남의 키)
307
+ * @throws InvalidKeyFingerprintError fingerprint가 publicKey와 맞지 않을 때
308
+ */
309
+ declare function registerPublicKeyService(params: RegisterPublicKeyParams): Promise<void>;
310
+ /**
311
+ * Rotate user's public key (revoke old, register new)
312
+ */
313
+ declare function rotateKeyService(params: RotateKeyParams): Promise<RotateKeyResult>;
314
+ /**
315
+ * Revoke a user's public key.
316
+ *
317
+ * Returns false when the key does not belong to this user, so a caller acting
318
+ * on a key id from outside (the device list) can answer "not found" instead of
319
+ * reporting a revocation that never happened. The repository already scopes the
320
+ * update by userId, so someone else's key is never touched either way.
321
+ */
322
+ declare function revokeKeyService(params: RevokeKeyParams): Promise<boolean>;
323
+ /**
324
+ * List the caller's active keys — one entry per device that can sign for them.
325
+ *
326
+ * `isExpired` is computed rather than stored: an expired key keeps `isActive`
327
+ * true (nothing flips it), and `authenticate` refuses it at request time. A list
328
+ * that showed it as simply "active" would be telling the user something the
329
+ * server does not act on.
330
+ *
331
+ * The fingerprint is truncated. Its full value is what a native sign-in must
332
+ * send as its nonce (issue #63), and an account page has no use for it beyond
333
+ * telling two entries apart.
334
+ */
335
+ declare function listKeysService(params: ListKeysParams): Promise<KeySummary[]>;
336
+ /**
337
+ * Revoke every active key the user has, optionally sparing the current one.
338
+ *
339
+ * The caller's own key is spared by default, so "sign out my other devices"
340
+ * does not also end the session making the request. Passing
341
+ * `includeCurrent: true` is the full sign-out, which until now was reachable
342
+ * only as a side effect of changing a password.
343
+ */
344
+ declare function revokeAllKeysService(params: RevokeAllKeysParams): Promise<RevokeAllKeysResult>;
345
+
346
+ /**
347
+ * @spfn/auth - RBAC Type Definitions
348
+ *
349
+ * Type definitions for role and permission configuration
350
+ */
351
+ /**
352
+ * Permission category enum values
353
+ * Single source of truth for permission categories
354
+ */
355
+ declare const PERMISSION_CATEGORIES: readonly ["auth", "user", "rbac", "system", "custom"];
356
+ /**
357
+ * Permission category type derived from the const array
358
+ */
359
+ type PermissionCategory = typeof PERMISSION_CATEGORIES[number];
360
+ interface RoleConfig {
361
+ name: string;
362
+ displayName: string;
363
+ description?: string;
364
+ priority?: number;
365
+ isSystem?: boolean;
366
+ isBuiltin?: boolean;
367
+ }
368
+ interface PermissionConfig {
369
+ name: string;
370
+ displayName: string;
371
+ description?: string;
372
+ category?: PermissionCategory;
373
+ isSystem?: boolean;
374
+ isBuiltin?: boolean;
375
+ }
376
+ interface AuthInitOptions {
377
+ /**
378
+ * Additional roles to create
379
+ * Built-in roles (user, admin, superadmin) are automatically included
380
+ */
381
+ roles?: RoleConfig[];
382
+ /**
383
+ * Additional permissions to create
384
+ * Built-in permissions are automatically included
385
+ */
386
+ permissions?: PermissionConfig[];
387
+ /**
388
+ * Role-Permission mappings
389
+ * Built-in mappings are automatically included
390
+ * You can extend built-in roles or define mappings for custom roles
391
+ *
392
+ * @example
393
+ * ```typescript
394
+ * {
395
+ * // Extend built-in admin role
396
+ * admin: ['project:create', 'project:delete'],
397
+ *
398
+ * // Define custom role permissions
399
+ * 'project-manager': ['project:create', 'task:assign'],
400
+ * }
401
+ * ```
402
+ */
403
+ rolePermissions?: Record<string, string[]>;
404
+ /**
405
+ * Default role name for new users
406
+ * Must be a valid role name that exists after initialization
407
+ * @default 'user'
408
+ */
409
+ defaultRole?: string;
410
+ /**
411
+ * Default session TTL (Time To Live)
412
+ *
413
+ * Supports:
414
+ * - Number: seconds (e.g., 2592000)
415
+ * - String: duration format ('30d', '12h', '45m', '3600s')
416
+ *
417
+ * Can be overridden at runtime with `remember` parameter.
418
+ *
419
+ * @default '7d' (7 days)
420
+ *
421
+ * @example
422
+ * ```typescript
423
+ * {
424
+ * sessionTtl: '30d', // 30 days
425
+ * }
426
+ * ```
427
+ */
428
+ sessionTtl?: string | number;
429
+ }
430
+
431
+ /**
432
+ * One-Time Token Service
433
+ *
434
+ * Issues and verifies one-time tokens for direct API access.
435
+ */
436
+ interface IssueOneTimeTokenResult {
437
+ token: string;
438
+ expiresAt: string;
439
+ }
440
+ /**
441
+ * Issue a one-time token for the authenticated user
442
+ *
443
+ * @param userId - Authenticated user's ID
444
+ * @returns Token string and ISO expiration timestamp
445
+ */
446
+ declare function issueOneTimeTokenService(userId: string): Promise<IssueOneTimeTokenResult>;
447
+ /**
448
+ * Verify and consume a one-time token
449
+ *
450
+ * @param token - The one-time token to verify
451
+ * @returns userId if valid, null if invalid/expired/consumed
452
+ */
453
+ declare function verifyOneTimeTokenService(token: string): Promise<string | null>;
454
+
455
+ /**
456
+ * OAuth Provider 추상화
457
+ *
458
+ * Provider별로 하드코딩된 분기를 제거하기 위한 공통 인터페이스와 registry.
459
+ * - 내장 provider(google)는 패키지 로드 시점에 자기 등록(dogfood)
460
+ * - 외부 패키지(@superself/auth 등)는 registerOAuthProvider()로 런타임 등록
461
+ *
462
+ * @spfn/auth는 토큰 issuer가 아니라 소비(client) 측이므로, 이 추상화는
463
+ * web 흐름("authorize URL 생성 → code 교환 → 사용자 정보 정규화")과
464
+ * native 흐름(네이티브/웹 SDK가 받은 id_token 직접 검증)을 다룬다.
465
+ */
466
+
467
+ /**
468
+ * Provider 사용자 정보를 공통 형태로 정규화한 신원
469
+ *
470
+ * provider별 응답 형태(snake_case 등)를 service에 노출하지 않기 위한 경계.
471
+ */
472
+ interface NormalizedIdentity {
473
+ providerUserId: string;
474
+ email: string | null;
475
+ emailVerified: boolean;
476
+ name?: string;
477
+ avatar?: string;
478
+ }
479
+ /**
480
+ * 정규화된 OAuth 토큰 응답
481
+ *
482
+ * @property expiresIn - access token 만료까지 남은 초(seconds)
483
+ */
484
+ interface OAuthTokens {
485
+ accessToken: string;
486
+ refreshToken?: string;
487
+ expiresIn: number;
488
+ }
489
+ /**
490
+ * 네이티브 id_token 검증 옵션
491
+ */
492
+ interface NativeVerifyOptions {
493
+ /** 클라이언트가 생성한 raw nonce. provider별 규약(raw 또는 SHA-256 해시)으로 대조된다. */
494
+ nonce: string;
495
+ /**
496
+ * 같은 로그인에서 SDK가 함께 받은 provider access token (선택).
497
+ *
498
+ * id_token만으로는 알 수 없는 claim을 provider API로 보강하려는 provider가 쓴다
499
+ * (카카오: id_token에 email_verified가 없어 /v2/user/me의 이메일 유효·인증 플래그를 본다).
500
+ *
501
+ * ⚠️ 클라이언트가 보낸 검증되지 않은 값이다. 다른 사용자의 토큰일 수 있으므로,
502
+ * 이 값으로 조회한 신원은 반드시 id_token의 sub와 대조한 뒤에만 신뢰해야 한다.
503
+ */
504
+ accessToken?: string;
505
+ }
506
+ interface OAuthCodeExchangeOptions {
507
+ /** Provider가 callback에 돌려준 원본 state. 일부 provider는 token 교환에도 요구한다. */
508
+ state: string;
509
+ }
510
+ /**
511
+ * Provider가 서비스로 보내는 연동 해제 알림의 원재료
512
+ *
513
+ * provider마다 전달 방식(query/form/JSON, 헤더 인증)이 달라 route가 정규화해 넘긴다.
514
+ * fields는 query string과 body(form/JSON)를 병합한 문자열 맵이다.
515
+ */
516
+ interface UnlinkNotifyRequest {
517
+ /** Authorization 헤더 원문 (없으면 null) */
518
+ authorization: string | null;
519
+ fields: Record<string, string>;
520
+ }
521
+ /**
522
+ * 검증에 성공한 연동 해제 알림
523
+ */
524
+ interface UnlinkNotification {
525
+ providerUserId: string;
526
+ /** provider가 전달한 해제 경로 (kakao referrer_type 등) */
527
+ reason?: string;
528
+ }
529
+ /**
530
+ * 연동 해제 알림 검증 실패
531
+ *
532
+ * API 에러 응답 체계를 타지 않는다 — route가 잡아 status만 반환한다.
533
+ * (provider 웹훅은 사람이 아닌 provider 서버가 호출자라서 에러 본문이 무의미하다)
534
+ */
535
+ declare class UnlinkNotifyRejection extends Error {
536
+ readonly status: 400 | 401 | 403;
537
+ constructor(status: 400 | 401 | 403, message: string);
538
+ }
539
+ /**
540
+ * OAuth provider 구현 인터페이스
541
+ *
542
+ * google, superself 등 모든 provider가 이 형태를 만족해야 registry에 등록된다.
543
+ */
544
+ interface OAuthProvider {
545
+ id: SocialProvider;
546
+ /**
547
+ * provider가 사용 가능한 상태인지(필수 env 등) 확인
548
+ */
549
+ isEnabled(): boolean;
550
+ /**
551
+ * provider 로그인 페이지로 보낼 authorization URL 생성
552
+ *
553
+ * @param state - CSRF 방지용 암호화 state
554
+ * @param scopes - 요청할 scope (미지정 시 provider 기본값)
555
+ */
556
+ getAuthUrl(state: string, scopes?: string[]): string;
557
+ /**
558
+ * authorization code를 토큰으로 교환
559
+ */
560
+ exchangeCodeForTokens(code: string, options: OAuthCodeExchangeOptions): Promise<OAuthTokens>;
561
+ /**
562
+ * access token으로 사용자 정보를 조회하고 공통 형태로 정규화
563
+ */
564
+ getUserInfo(accessToken: string): Promise<NormalizedIdentity>;
565
+ /**
566
+ * refresh token으로 access token 갱신 (provider가 지원하는 경우)
567
+ *
568
+ * 저장된 provider 토큰을 이후 API 호출에 재사용할 때 사용한다.
569
+ * 미구현 provider는 갱신 불가로 간주한다.
570
+ */
571
+ refreshTokens?(refreshToken: string): Promise<OAuthTokens>;
572
+ /**
573
+ * 네이티브/웹 SDK가 받은 id_token을 직접 검증하고 신원을 정규화한다.
574
+ *
575
+ * authorization code 교환 없이 provider JWKS로 서명을 검증하므로 client secret이
576
+ * 필요 없다. native sign-in을 지원하는 provider만 구현한다(Apple은 web SDK 부재로
577
+ * Android·웹도 이 경로를 쓴다).
578
+ */
579
+ verifyNativeIdToken?(idToken: string, options: NativeVerifyOptions): Promise<NormalizedIdentity>;
580
+ /**
581
+ * Provider발 연동 해제 알림(웹훅)을 검증하고 대상 사용자를 식별한다.
582
+ *
583
+ * 인증 없는 공개 엔드포인트로 들어오므로 provider별 규격(카카오: 어드민 키 헤더,
584
+ * 네이버: HMAC 서명 + AES 복호화)의 검증을 통과해야만 처리된다.
585
+ * 검증 실패는 UnlinkNotifyRejection을 던진다.
586
+ */
587
+ verifyUnlinkNotification?(request: UnlinkNotifyRequest): Promise<UnlinkNotification>;
588
+ /**
589
+ * 연동 해제 알림 처리 성공 시 응답할 HTTP status (미지정 시 200)
590
+ *
591
+ * 네이버는 204 No Content를 요구한다.
592
+ */
593
+ unlinkNotifyAckStatus?: 200 | 204;
594
+ }
595
+ /**
596
+ * OAuth provider 등록 (public)
597
+ *
598
+ * 동일 id로 다시 등록하면 덮어쓴다(외부 패키지의 override 허용).
599
+ */
600
+ declare function registerOAuthProvider(provider: OAuthProvider): void;
601
+ /**
602
+ * 등록된 provider 조회. 미등록이면 undefined.
603
+ */
604
+ declare function getOAuthProvider(id: SocialProvider): OAuthProvider | undefined;
605
+ /**
606
+ * 등록된 모든 provider 목록
607
+ */
608
+ declare function getRegisteredProviders(): OAuthProvider[];
609
+
610
+ /**
611
+ * @spfn/auth - OAuth Service
612
+ *
613
+ * OAuth 인증 비즈니스 로직
614
+ * - Google OAuth Authorization Code Flow
615
+ * - 소셜 계정 연결/생성
616
+ * - publicKey는 state에서 추출하여 등록
617
+ */
618
+
619
+ interface OAuthStartParams {
620
+ provider: SocialProvider;
621
+ returnUrl: string;
622
+ publicKey: string;
623
+ keyId: string;
624
+ fingerprint: string;
625
+ algorithm: KeyAlgorithmType;
626
+ metadata?: Record<string, unknown>;
627
+ /** CSRF nonce bound into the state; the route sets the matching oauth_csrf cookie. */
628
+ nonce?: string;
629
+ }
630
+ interface OAuthStartResult {
631
+ authUrl: string;
632
+ }
633
+ interface OAuthCallbackParams {
634
+ provider: SocialProvider;
635
+ code: string;
636
+ state: string;
637
+ /**
638
+ * Value(s) of the oauth_csrf cookie from the callback request. One of them
639
+ * must equal the nonce bound into the (encrypted) state — otherwise the flow
640
+ * wasn't initiated by this browser (login CSRF). An array arises because the
641
+ * cookie name carries the PORT suffix of the process that set it (the Next.js
642
+ * web process), which differs from the API process in a split deployment, so
643
+ * the callback collects every spfn_oauth_csrf* candidate. Pass `undefined` or
644
+ * an empty array when absent; verification then fails closed.
645
+ */
646
+ expectedNonce: string | string[] | undefined;
647
+ }
648
+ interface OAuthCallbackResult {
649
+ redirectUrl: string;
650
+ userId: string;
651
+ keyId: string;
652
+ isNewUser: boolean;
653
+ }
654
+ /**
655
+ * registry에서 provider를 찾아 사용 가능한지 검증 후 반환
656
+ *
657
+ * 미등록과 비활성을 구분해 디버깅 신호를 남긴다.
658
+ * 라우트 레이어에서도 재사용한다(중복 조회/non-null 단언 제거).
659
+ */
660
+ declare function requireEnabledProvider(provider: SocialProvider): OAuthProvider;
661
+ /**
662
+ * OAuth 로그인 시작 - Provider 로그인 페이지로 리다이렉트할 URL 생성
663
+ *
664
+ * Next.js에서 키쌍을 생성한 후, publicKey를 state에 포함하여 호출
665
+ */
666
+ declare function oauthStartService(params: OAuthStartParams): Promise<OAuthStartResult>;
667
+ /**
668
+ * OAuth 콜백 처리 - Code를 Token으로 교환하고 사용자 생성/연결
669
+ *
670
+ * state에서 publicKey를 추출하여 서버에 등록
671
+ * Next.js는 반환된 userId, keyId로 세션을 구성
672
+ */
673
+ declare function oauthCallbackService(params: OAuthCallbackParams): Promise<OAuthCallbackResult>;
674
+ /**
675
+ * OAuth 에러 리다이렉트 URL 생성
676
+ */
677
+ declare function buildOAuthErrorUrl(error: string): string;
678
+ /**
679
+ * OAuth provider가 등록되어 있고 활성화되어 있는지 확인
680
+ */
681
+ declare function isOAuthProviderEnabled(provider: SocialProvider): boolean;
682
+ /**
683
+ * 활성화된 모든 OAuth provider 목록 (registry 기반)
684
+ */
685
+ declare function getEnabledOAuthProviders(): SocialProvider[];
686
+ /**
687
+ * Google access token 조회 (만료 시 자동 리프레시)
688
+ *
689
+ * 저장된 토큰이 만료 임박(5분 이내) 또는 만료 상태이면
690
+ * refresh token으로 자동 갱신 후 DB 업데이트하여 유효한 토큰 반환.
691
+ *
692
+ * @param userId - 사용자 ID
693
+ * @returns 유효한 Google access token
694
+ */
695
+ declare function getGoogleAccessToken(userId: number): Promise<string>;
696
+ interface UnlinkNotifyResult {
697
+ /** provider 규격이 요구하는 성공 응답 status */
698
+ ackStatus: 200 | 204;
699
+ /** 대상 소셜 계정을 찾아 삭제했는지 (미존재·이미 삭제면 false) */
700
+ handled: boolean;
701
+ }
702
+ /**
703
+ * Provider발 연동 해제 알림(unlink-notify) 처리
704
+ *
705
+ * 검증(verifyUnlinkNotification)을 통과한 요청만 여기 도달한다.
706
+ * 소셜 계정 연결 row를 삭제해 저장 토큰(access/refresh)까지 함께 파기하고,
707
+ * 후속 정책(계정 탈퇴 연계 등)은 auth.oauth.unlinked 이벤트 구독에 맡긴다.
708
+ *
709
+ * 대상 계정이 없어도 성공으로 응답한다 — provider 재전송·이미 해제된 계정에
710
+ * 대한 알림은 정상 시나리오다.
711
+ */
712
+ declare function oauthUnlinkNotifyService(provider: SocialProvider, notification: UnlinkNotification): Promise<UnlinkNotifyResult>;
713
+
714
+ /**
715
+ * @spfn/auth - Native Social Login Service
716
+ *
717
+ * 네이티브/웹 SDK가 받은 id_token을 JWKS로 검증하고, 검증된 신원에 클라이언트가 만든
718
+ * 공개키를 등록한다. 토큰은 발급하지 않는다 — 클라이언트가 등록한 키로 client token을
719
+ * 직접 서명해 Bearer로 사용한다(client-signs / server-verifies 모델).
720
+ *
721
+ * 흐름은 두 단계로 분리한다:
722
+ * 1) id_token 검증 — 외부 JWKS 네트워크 조회. DB 트랜잭션 밖에서 수행한다.
723
+ * 2) persist — 사용자 link/create + 공개키 등록을 한 트랜잭션으로. 이벤트는 커밋 후 발행.
724
+ */
725
+
726
+ interface OAuthNativeParams {
727
+ provider: SocialProvider;
728
+ idToken: string;
729
+ nonce: string;
730
+ publicKey: string;
731
+ keyId: string;
732
+ fingerprint: string;
733
+ algorithm: KeyAlgorithmType;
734
+ /** 키 목록에 보일 기기 라벨 (선택). 표시용이라 권한 판정에 쓰이지 않는다. */
735
+ deviceName?: string;
736
+ platform?: KeyPlatformType;
737
+ /**
738
+ * SDK가 id_token과 함께 받은 provider access token (선택).
739
+ *
740
+ * provider가 id_token만으로 확인할 수 없는 claim을 보강할 때만 쓴다. 없으면 provider는
741
+ * id_token이 담은 정보만으로 신원을 정규화한다.
742
+ */
743
+ accessToken?: string;
744
+ /** Apple은 첫 로그인에만 이름을 별도로 주므로 클라이언트가 전달할 수 있다. */
745
+ profile?: {
746
+ name?: string;
747
+ };
748
+ metadata?: Record<string, unknown>;
749
+ }
750
+ interface OAuthNativeResult {
751
+ userId: string;
752
+ keyId: string;
753
+ isNewUser: boolean;
754
+ }
755
+ /**
756
+ * native id_token 로그인 처리
757
+ *
758
+ * @throws NativeSignInUnsupportedError provider가 native sign-in을 지원하지 않을 때
759
+ * @throws InvalidSocialTokenError id_token 검증 실패 시
760
+ */
761
+ declare function oauthNativeService(params: OAuthNativeParams): Promise<OAuthNativeResult>;
762
+
763
+ /**
764
+ * @spfn/auth - Main Router
765
+ *
766
+ * Combines all auth-related routes into a single router
767
+ */
768
+ /**
769
+ * Main auth router
770
+ * Exports all authentication-related routes
771
+ *
772
+ * Routes:
773
+ * - Auth: /_auth/codes, /_auth/login, /_auth/logout, etc.
774
+ * - OAuth: /_auth/oauth/google, /_auth/oauth/google/callback, etc.
775
+ * - Invitations: /_auth/invitations/*
776
+ * - Users: /_auth/users/*
777
+ * - Deletion: /_auth/deletion/request, /_auth/deletion/cancel
778
+ * - Admin: /_auth/admin/* (superadmin only)
779
+ */
780
+ declare const mainAuthRouter: _spfn_core_route.Router<{
781
+ sendVerificationCode: _spfn_core_route.RouteDef<{
782
+ body: _sinclair_typebox.TObject<{
783
+ target: _sinclair_typebox.TString;
784
+ targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
785
+ purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">, _sinclair_typebox.TLiteral<"account_deletion">]>;
786
+ }>;
787
+ }, {}, SendVerificationCodeResult>;
788
+ verifyCode: _spfn_core_route.RouteDef<{
789
+ body: _sinclair_typebox.TObject<{
790
+ target: _sinclair_typebox.TString;
791
+ targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
792
+ code: _sinclair_typebox.TString;
793
+ purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">, _sinclair_typebox.TLiteral<"account_deletion">]>;
794
+ }>;
795
+ }, {}, {
796
+ valid: boolean;
797
+ verificationToken: string;
798
+ }>;
799
+ register: _spfn_core_route.RouteDef<{
800
+ body: _sinclair_typebox.TObject<{
801
+ email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
802
+ phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
803
+ verificationToken: _sinclair_typebox.TString;
804
+ password: _sinclair_typebox.TString;
805
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
806
+ }>;
807
+ }, {
808
+ body: _sinclair_typebox.TObject<{
809
+ publicKey: _sinclair_typebox.TString;
810
+ keyId: _sinclair_typebox.TString;
811
+ fingerprint: _sinclair_typebox.TString;
812
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
813
+ deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
814
+ platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
815
+ }>;
816
+ }, RegisterResult>;
817
+ login: _spfn_core_route.RouteDef<{
818
+ body: _sinclair_typebox.TObject<{
819
+ email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
820
+ phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
821
+ password: _sinclair_typebox.TString;
822
+ }>;
823
+ }, {
824
+ body: _sinclair_typebox.TObject<{
825
+ publicKey: _sinclair_typebox.TString;
826
+ keyId: _sinclair_typebox.TString;
827
+ fingerprint: _sinclair_typebox.TString;
828
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
829
+ oldKeyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
830
+ deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
831
+ platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
832
+ }>;
833
+ }, LoginResult>;
834
+ logout: _spfn_core_route.RouteDef<{}, {}, void>;
835
+ rotateKey: _spfn_core_route.RouteDef<{}, {
836
+ body: _sinclair_typebox.TObject<{
837
+ publicKey: _sinclair_typebox.TString;
838
+ keyId: _sinclair_typebox.TString;
839
+ fingerprint: _sinclair_typebox.TString;
840
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
841
+ deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
842
+ platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
843
+ }>;
844
+ }, RotateKeyResult>;
845
+ listKeys: _spfn_core_route.RouteDef<{
846
+ body: _sinclair_typebox.TObject<{
847
+ includeRevoked: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
848
+ }>;
849
+ }, {}, {
850
+ keys: KeySummary[];
851
+ }>;
852
+ revokeKey: _spfn_core_route.RouteDef<{
853
+ body: _sinclair_typebox.TObject<{
854
+ keyId: _sinclair_typebox.TString;
855
+ }>;
856
+ }, {}, {
857
+ keyId: string;
858
+ selfRevoked: boolean;
859
+ }>;
860
+ revokeAllKeys: _spfn_core_route.RouteDef<{
861
+ body: _sinclair_typebox.TObject<{
862
+ includeCurrent: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
863
+ }>;
864
+ }, {}, RevokeAllKeysResult>;
865
+ changePassword: _spfn_core_route.RouteDef<{
866
+ body: _sinclair_typebox.TObject<{
867
+ currentPassword: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
868
+ newPassword: _sinclair_typebox.TString;
869
+ }>;
870
+ }, {}, void>;
871
+ getAuthSession: _spfn_core_route.RouteDef<{}, {}, {
872
+ role: {
873
+ id: number;
874
+ name: string;
875
+ displayName: string;
876
+ priority: number;
877
+ };
878
+ permissions: {
879
+ id: number;
880
+ name: string;
881
+ displayName: string;
882
+ category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
883
+ }[];
884
+ userId: number;
885
+ publicId: string;
886
+ email: string | null;
887
+ emailVerified: boolean;
888
+ phoneVerified: boolean;
889
+ hasPassword: boolean;
890
+ }>;
891
+ issueOneTimeToken: _spfn_core_route.RouteDef<{}, {}, IssueOneTimeTokenResult>;
892
+ requestAccountDeletion: _spfn_core_route.RouteDef<{
893
+ body: _sinclair_typebox.TObject<{
894
+ password: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
895
+ verificationToken: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
896
+ reason: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
897
+ immediate: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
898
+ }>;
899
+ }, {}, {
900
+ purgeScheduledAt: string;
901
+ }>;
902
+ cancelAccountDeletion: _spfn_core_route.RouteDef<{
903
+ body: _sinclair_typebox.TObject<{
904
+ email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
905
+ phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
906
+ password: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
907
+ verificationToken: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
908
+ }>;
909
+ }, {}, void>;
910
+ oauthGoogleStart: _spfn_core_route.RouteDef<{
911
+ query: _sinclair_typebox.TObject<{
912
+ state: _sinclair_typebox.TString;
913
+ }>;
914
+ }, {}, Response>;
915
+ oauthGoogleCallback: _spfn_core_route.RouteDef<{
916
+ query: _sinclair_typebox.TObject<{
917
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
918
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
919
+ error: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
920
+ error_description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
921
+ }>;
922
+ }, {}, Response>;
923
+ oauthStart: _spfn_core_route.RouteDef<{
924
+ body: _sinclair_typebox.TObject<{
925
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
926
+ returnUrl: _sinclair_typebox.TString;
927
+ publicKey: _sinclair_typebox.TString;
928
+ keyId: _sinclair_typebox.TString;
929
+ fingerprint: _sinclair_typebox.TString;
930
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
931
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
932
+ }>;
933
+ }, {}, OAuthStartResult>;
934
+ oauthProviders: _spfn_core_route.RouteDef<{}, {}, {
935
+ providers: ("google" | "apple" | "github" | "kakao" | "naver" | "superself")[];
936
+ }>;
937
+ getGoogleOAuthUrl: _spfn_core_route.RouteDef<{
938
+ body: _sinclair_typebox.TObject<{
939
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
940
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
941
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
942
+ }>;
943
+ }, {}, {
944
+ authUrl: string;
945
+ }>;
946
+ oauthFinalize: _spfn_core_route.RouteDef<{
947
+ body: _sinclair_typebox.TObject<{
948
+ userId: _sinclair_typebox.TString;
949
+ keyId: _sinclair_typebox.TString;
950
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
951
+ }>;
952
+ }, {}, {
953
+ success: boolean;
954
+ userId: string;
955
+ keyId: string;
956
+ returnUrl: string;
957
+ }>;
958
+ oauthProviderStart: _spfn_core_route.RouteDef<{
959
+ params: _sinclair_typebox.TObject<{
960
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
961
+ }>;
962
+ query: _sinclair_typebox.TObject<{
963
+ state: _sinclair_typebox.TString;
964
+ }>;
965
+ }, {}, Response>;
966
+ oauthProviderCallback: _spfn_core_route.RouteDef<{
967
+ params: _sinclair_typebox.TObject<{
968
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
969
+ }>;
970
+ query: _sinclair_typebox.TObject<{
971
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
972
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
973
+ error: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
974
+ error_description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
975
+ }>;
976
+ }, {}, Response>;
977
+ getProviderOAuthUrl: _spfn_core_route.RouteDef<{
978
+ params: _sinclair_typebox.TObject<{
979
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
980
+ }>;
981
+ body: _sinclair_typebox.TObject<{
982
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
983
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
984
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
985
+ }>;
986
+ }, {}, {
987
+ authUrl: string;
988
+ }>;
989
+ oauthNative: _spfn_core_route.RouteDef<{
990
+ params: _sinclair_typebox.TObject<{
991
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
992
+ }>;
993
+ body: _sinclair_typebox.TObject<{
994
+ idToken: _sinclair_typebox.TString;
995
+ nonce: _sinclair_typebox.TString;
996
+ accessToken: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
997
+ publicKey: _sinclair_typebox.TString;
998
+ keyId: _sinclair_typebox.TString;
999
+ fingerprint: _sinclair_typebox.TString;
1000
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
1001
+ deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1002
+ platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
1003
+ profile: _sinclair_typebox.TOptional<_sinclair_typebox.TObject<{
1004
+ name: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1005
+ }>>;
1006
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
1007
+ }>;
1008
+ }, {}, OAuthNativeResult>;
1009
+ oauthUnlinkNotify: _spfn_core_route.RouteDef<{
1010
+ params: _sinclair_typebox.TObject<{
1011
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
1012
+ }>;
1013
+ }, {}, void | Response>;
1014
+ oauthUnlinkNotifyGet: _spfn_core_route.RouteDef<{
1015
+ params: _sinclair_typebox.TObject<{
1016
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
1017
+ }>;
1018
+ }, {}, void | Response>;
1019
+ getInvitation: _spfn_core_route.RouteDef<{
1020
+ params: _sinclair_typebox.TObject<{
1021
+ token: _sinclair_typebox.TString;
1022
+ }>;
1023
+ }, {}, {
1024
+ email: string;
1025
+ role: string;
1026
+ roleDisplayName: string;
1027
+ invitedBy: string;
1028
+ expiresAt: string;
1029
+ metadata: Record<string, any> | undefined;
1030
+ }>;
1031
+ acceptInvitation: _spfn_core_route.RouteDef<{
1032
+ body: _sinclair_typebox.TObject<{
1033
+ token: _sinclair_typebox.TString;
1034
+ password: _sinclair_typebox.TString;
1035
+ }>;
1036
+ }, {
1037
+ body: _sinclair_typebox.TObject<{
1038
+ publicKey: _sinclair_typebox.TString;
1039
+ keyId: _sinclair_typebox.TString;
1040
+ fingerprint: _sinclair_typebox.TString;
1041
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
1042
+ }>;
1043
+ }, {
1044
+ userId: number;
1045
+ email: string;
1046
+ role: string;
1047
+ }>;
1048
+ createInvitation: _spfn_core_route.RouteDef<{
1049
+ body: _sinclair_typebox.TObject<{
1050
+ email: _sinclair_typebox.TString;
1051
+ roleId: _sinclair_typebox.TNumber;
1052
+ expiresInDays: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1053
+ expiresAt: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1054
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TAny>;
1055
+ }>;
1056
+ }, {}, {
1057
+ id: number;
1058
+ email: string;
1059
+ token: string;
1060
+ roleId: number;
1061
+ expiresAt: string;
1062
+ invitationUrl: string;
1063
+ }>;
1064
+ listInvitations: _spfn_core_route.RouteDef<{
1065
+ query: _sinclair_typebox.TObject<{
1066
+ status: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"pending" | "accepted" | "expired" | "cancelled">[]>>;
1067
+ page: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1068
+ limit: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1069
+ }>;
1070
+ }, {}, {
1071
+ invitations: {
1072
+ id: number;
1073
+ email: string;
1074
+ token: string;
1075
+ roleId: number;
1076
+ invitedBy: number;
1077
+ status: "pending" | "accepted" | "expired" | "cancelled";
1078
+ expiresAt: Date;
1079
+ acceptedAt: Date | null;
1080
+ cancelledAt: Date | null;
1081
+ metadata: Record<string, any> | null;
1082
+ createdAt: Date;
1083
+ updatedAt: Date;
1084
+ role: {
1085
+ id: number;
1086
+ name: string;
1087
+ displayName: string;
1088
+ };
1089
+ inviter: {
1090
+ id: number;
1091
+ email: string | null;
1092
+ };
1093
+ }[];
1094
+ total: number;
1095
+ page: number;
1096
+ limit: number;
1097
+ totalPages: number;
1098
+ }>;
1099
+ cancelInvitation: _spfn_core_route.RouteDef<{
1100
+ body: _sinclair_typebox.TObject<{
1101
+ id: _sinclair_typebox.TNumber;
1102
+ reason: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1103
+ }>;
1104
+ }, {}, {
1105
+ cancelledAt: string;
1106
+ }>;
1107
+ resendInvitation: _spfn_core_route.RouteDef<{
1108
+ body: _sinclair_typebox.TObject<{
1109
+ id: _sinclair_typebox.TNumber;
1110
+ expiresInDays: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1111
+ }>;
1112
+ }, {}, {
1113
+ expiresAt: string;
1114
+ }>;
1115
+ deleteInvitation: _spfn_core_route.RouteDef<{
1116
+ body: _sinclair_typebox.TObject<{
1117
+ id: _sinclair_typebox.TNumber;
1118
+ }>;
1119
+ }, {}, void>;
1120
+ getUserProfile: _spfn_core_route.RouteDef<{}, {}, UserProfile>;
1121
+ updateUserProfile: _spfn_core_route.RouteDef<{
1122
+ body: _sinclair_typebox.TObject<{
1123
+ displayName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1124
+ firstName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1125
+ lastName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1126
+ avatarUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1127
+ bio: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1128
+ locale: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1129
+ timezone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1130
+ dateOfBirth: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1131
+ gender: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1132
+ website: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1133
+ location: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1134
+ company: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1135
+ jobTitle: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1136
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TAny>>;
1137
+ }>;
1138
+ }, {}, ProfileInfo>;
1139
+ checkUsername: _spfn_core_route.RouteDef<{
1140
+ query: _sinclair_typebox.TObject<{
1141
+ username: _sinclair_typebox.TString;
1142
+ }>;
1143
+ }, {}, {
1144
+ available: boolean;
1145
+ }>;
1146
+ updateUsername: _spfn_core_route.RouteDef<{
1147
+ body: _sinclair_typebox.TObject<{
1148
+ username: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
1149
+ }>;
1150
+ }, {}, {
1151
+ deletedAt: Date | null;
1152
+ deletedBy: string | null;
1153
+ createdAt: Date;
1154
+ updatedAt: Date;
1155
+ id: number;
1156
+ publicId: string;
1157
+ email: string | null;
1158
+ phone: string | null;
1159
+ username: string | null;
1160
+ passwordHash: string | null;
1161
+ passwordChangeRequired: boolean;
1162
+ roleId: number;
1163
+ status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
1164
+ emailVerifiedAt: Date | null;
1165
+ phoneVerifiedAt: Date | null;
1166
+ lastLoginAt: Date | null;
1167
+ }>;
1168
+ updateLocale: _spfn_core_route.RouteDef<{
1169
+ body: _sinclair_typebox.TObject<{
1170
+ locale: _sinclair_typebox.TString;
1171
+ }>;
1172
+ }, {}, {
1173
+ locale: string;
1174
+ }>;
1175
+ listRoles: _spfn_core_route.RouteDef<{
1176
+ query: _sinclair_typebox.TObject<{
1177
+ includeInactive: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
1178
+ }>;
1179
+ }, {}, {
1180
+ roles: {
1181
+ description: string | null;
1182
+ name: string;
1183
+ id: number;
1184
+ displayName: string;
1185
+ isBuiltin: boolean;
1186
+ isSystem: boolean;
1187
+ isActive: boolean;
1188
+ priority: number;
1189
+ createdAt: Date;
1190
+ updatedAt: Date;
1191
+ }[];
1192
+ }>;
1193
+ createAdminRole: _spfn_core_route.RouteDef<{
1194
+ body: _sinclair_typebox.TObject<{
1195
+ name: _sinclair_typebox.TString;
1196
+ displayName: _sinclair_typebox.TString;
1197
+ description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1198
+ priority: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1199
+ permissionIds: _sinclair_typebox.TOptional<_sinclair_typebox.TArray<_sinclair_typebox.TNumber>>;
1200
+ }>;
1201
+ }, {}, {
1202
+ role: {
1203
+ description: string | null;
1204
+ name: string;
1205
+ id: number;
1206
+ displayName: string;
1207
+ isBuiltin: boolean;
1208
+ isSystem: boolean;
1209
+ isActive: boolean;
1210
+ priority: number;
1211
+ createdAt: Date;
1212
+ updatedAt: Date;
1213
+ };
1214
+ }>;
1215
+ updateAdminRole: _spfn_core_route.RouteDef<{
1216
+ params: _sinclair_typebox.TObject<{
1217
+ id: _sinclair_typebox.TNumber;
1218
+ }>;
1219
+ body: _sinclair_typebox.TObject<{
1220
+ displayName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1221
+ description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
1222
+ priority: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
1223
+ isActive: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
1224
+ }>;
1225
+ }, {}, {
1226
+ role: {
1227
+ description: string | null;
1228
+ name: string;
1229
+ id: number;
1230
+ displayName: string;
1231
+ isBuiltin: boolean;
1232
+ isSystem: boolean;
1233
+ isActive: boolean;
1234
+ priority: number;
1235
+ createdAt: Date;
1236
+ updatedAt: Date;
1237
+ };
1238
+ }>;
1239
+ deleteAdminRole: _spfn_core_route.RouteDef<{
1240
+ params: _sinclair_typebox.TObject<{
1241
+ id: _sinclair_typebox.TNumber;
1242
+ }>;
1243
+ }, {}, void>;
1244
+ updateUserRole: _spfn_core_route.RouteDef<{
1245
+ params: _sinclair_typebox.TObject<{
1246
+ userId: _sinclair_typebox.TNumber;
1247
+ }>;
1248
+ body: _sinclair_typebox.TObject<{
1249
+ roleId: _sinclair_typebox.TNumber;
1250
+ }>;
1251
+ }, {}, {
1252
+ userId: number;
1253
+ roleId: number;
1254
+ }>;
1255
+ issueOpsToken: _spfn_core_route.RouteDef<{
1256
+ body: _sinclair_typebox.TObject<{
1257
+ name: _sinclair_typebox.TString;
1258
+ scopes: _sinclair_typebox.TArray<_sinclair_typebox.TString>;
1259
+ expiresInDays: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<[_sinclair_typebox.TNumber, _sinclair_typebox.TNull]>>;
1260
+ }>;
1261
+ }, {}, {
1262
+ token: string;
1263
+ opsToken: {
1264
+ id: number;
1265
+ name: string;
1266
+ scopes: string[];
1267
+ expiresAt: string | null;
1268
+ revokedAt: string | null;
1269
+ lastUsedAt: string | null;
1270
+ createdAt: string | null;
1271
+ };
1272
+ }>;
1273
+ listOpsTokens: _spfn_core_route.RouteDef<{}, {}, {
1274
+ opsTokens: {
1275
+ id: number;
1276
+ name: string;
1277
+ scopes: string[];
1278
+ expiresAt: string | null;
1279
+ revokedAt: string | null;
1280
+ lastUsedAt: string | null;
1281
+ createdAt: string | null;
1282
+ }[];
1283
+ }>;
1284
+ revokeOpsToken: _spfn_core_route.RouteDef<{
1285
+ params: _sinclair_typebox.TObject<{
1286
+ id: _sinclair_typebox.TNumber;
1287
+ }>;
1288
+ }, {}, {
1289
+ opsToken: {
1290
+ id: number;
1291
+ name: string;
1292
+ scopes: string[];
1293
+ expiresAt: string | null;
1294
+ revokedAt: string | null;
1295
+ lastUsedAt: string | null;
1296
+ createdAt: string | null;
1297
+ };
1298
+ }>;
1299
+ }>;
1300
+
1301
+ /**
1302
+ * The auth-profile registry the authenticate middleware dispatches on.
1303
+ *
1304
+ * A request that names `x-spfn-auth-profile` is answered by the verifier
1305
+ * registered for that profile — an O(1) map lookup, never a per-profile if
1306
+ * chain in the middleware body. A request that names no profile falls through
1307
+ * to the existing Bearer path untouched.
1308
+ *
1309
+ * Every verifier converges on the same `AuthContext` the Bearer path sets, so
1310
+ * downstream permission/tenant code consumes one principal shape and never
1311
+ * branches on how it was authenticated.
1312
+ *
1313
+ * The clientProofV1 verifier reuses the phase-1 admission pieces (header
1314
+ * shape, canonical body, proof-input assembly, ECDSA verification) with two
1315
+ * production substitutions: the key directory is `user_public_keys` via
1316
+ * `keysRepository`, and the replay ledger is the pluggable store from
1317
+ * `client-proof/replay-store` (memory default, Redis opt-in). The admission
1318
+ * order is the contract's — revocation → session → expiry → replay → proof —
1319
+ * and the non-disclosure rule holds: an unregistered keyId shares
1320
+ * PROOF_INVALID with a failed signature, while a revoked or expired key
1321
+ * answers SESSION_REVOKED before the proof is ever examined.
1322
+ *
1323
+ * @module server/middleware/auth-profiles
1324
+ */
1325
+
1326
+ /** What a verified request leaves in the context — one shape for every scheme. */
1327
+ interface AuthContext {
1328
+ user: User;
1329
+ userId: string;
1330
+ keyId: string;
1331
+ role: string | null;
1332
+ locale: string;
1333
+ /** How the principal was authenticated. Informational — downstream code never branches on it. */
1334
+ scheme: 'bearer' | 'clientProofV1' | 'oneTimeToken';
1335
+ }
1336
+ /** A profile's verifier: admits the request and returns the principal, or throws. */
1337
+ interface AuthProfileVerifier {
1338
+ verify(c: Context): Promise<AuthContext>;
1339
+ }
1340
+ /**
1341
+ * Routes a request to its profile verifier.
1342
+ *
1343
+ * - no profile header → null: the caller continues on the Bearer path;
1344
+ * - profile header + Authorization header → rejected (mixing prohibited);
1345
+ * - unknown profile value → rejected (unknownProfilePolicy: reject).
1346
+ *
1347
+ * Shared by authenticate and optionalAuth so "presented but invalid" refuses
1348
+ * identically on both — only the "presented nothing" outcome differs.
1349
+ */
1350
+ declare function selectAuthProfile(c: Context): AuthProfileVerifier | null;
1351
+ /**
1352
+ * Loads the user for an authenticated key and applies the account-status
1353
+ * rules. One implementation for every scheme: the Bearer path and the profile
1354
+ * verifiers call this, so a status added here gates both identically.
1355
+ */
1356
+ declare function resolveAuthenticatedUser(userId: number): Promise<{
1357
+ user: User;
1358
+ role: string | null;
1359
+ locale: string;
1360
+ }>;
1361
+ /** What the profile path produced for one request. */
1362
+ type AuthProfileOutcome = {
1363
+ kind: 'none';
1364
+ } | {
1365
+ kind: 'authenticated';
1366
+ auth: AuthContext;
1367
+ } | {
1368
+ kind: 'refused';
1369
+ response: Response;
1370
+ };
1371
+ /**
1372
+ * The profile path from dispatch to answer — what `authenticate` and
1373
+ * `optionalAuth` both run before their own Bearer code.
1374
+ *
1375
+ * `none` means the request named no profile and the caller continues on the
1376
+ * Bearer path. A refusal comes back as a built response rather than a throw:
1377
+ * the answer a proven call gets is the contract's own envelope, and an error
1378
+ * handed to the generic error handler is classified by its class name instead.
1379
+ */
1380
+ declare function runAuthProfile(c: Context): Promise<AuthProfileOutcome>;
1381
+
1382
+ declare module 'hono' {
1383
+ interface ContextVariableMap {
1384
+ auth: AuthContext;
1385
+ }
1386
+ }
1387
+ /**
1388
+ * Authentication middleware
1389
+ *
1390
+ * Verifies client-signed JWT token using stored public key
1391
+ * Must be applied to routes that require authentication
1392
+ *
1393
+ * @example
1394
+ * ```typescript
1395
+ * // In server.config.ts
1396
+ * import { authenticate } from '@spfn/auth/server/middleware';
1397
+ *
1398
+ * export default defineServerConfig()
1399
+ * .middlewares([authenticate])
1400
+ * .routes(appRouter)
1401
+ * .build();
1402
+ *
1403
+ * // In route file - skip auth for public routes
1404
+ * export const publicRoute = route.get('/health')
1405
+ * .skip(['auth']) // Type-safe skip
1406
+ * .handler(async (c) => c.success({ status: 'ok' }));
1407
+ *
1408
+ * // Protected route - auth applied automatically
1409
+ * export const protectedRoute = route.get('/profile')
1410
+ * .handler(async (c) => {
1411
+ * const auth = c.get('auth'); // Get auth context
1412
+ * const { user, userId, keyId } = auth;
1413
+ * // Or access directly: c.get('auth').user
1414
+ * });
1415
+ * ```
1416
+ */
1417
+ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
1418
+ /**
1419
+ * Optional authentication middleware
1420
+ *
1421
+ * Same as `authenticate` but does NOT reject unauthenticated requests.
1422
+ * - No token → continues without auth context
1423
+ * - Invalid token → continues without auth context
1424
+ * - Valid token → sets auth context normally
1425
+ *
1426
+ * Auto-skips the global 'auth' middleware when used at route level.
1427
+ *
1428
+ * @example
1429
+ * ```typescript
1430
+ * // No need for .skip(['auth']) — handled automatically
1431
+ * export const getProducts = route.get('/products')
1432
+ * .use([optionalAuth])
1433
+ * .handler(async (c) => {
1434
+ * const auth = getOptionalAuth(c); // AuthContext | undefined
1435
+ *
1436
+ * if (auth)
1437
+ * {
1438
+ * return getPersonalizedProducts(auth.userId);
1439
+ * }
1440
+ *
1441
+ * return getPublicProducts();
1442
+ * });
1443
+ * ```
1444
+ */
1445
+ declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
1446
+
1447
+ export { type UnlinkNotifyResult as $, type AuthInitOptions as A, PasswordSchema as B, type ChangePasswordParams as C, DeviceNameSchema as D, EmailSchema as E, PhoneSchema as F, PlatformSchema as G, type RegisterParams as H, type IssueOneTimeTokenResult as I, type RegisterPublicKeyParams as J, type KeySummary as K, type LoginResult as L, type RevokeAllKeysParams as M, type NativeVerifyOptions as N, type OAuthStartResult as O, type PermissionConfig as P, type RevokeKeyParams as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RotateKeyParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type SendVerificationCodeParams as W, TargetTypeSchema as X, type UnlinkNotification as Y, UnlinkNotifyRejection as Z, type UnlinkNotifyRequest as _, type RegisterResult as a, VerificationPurposeSchema as a0, type VerifyCodeParams as a1, type VerifyCodeResult as a2, authenticate as a3, buildOAuthErrorUrl as a4, changePasswordService as a5, getEnabledOAuthProviders as a6, getGoogleAccessToken as a7, getOAuthProvider as a8, getRegisteredProviders as a9, isOAuthProviderEnabled as aa, issueOneTimeTokenService as ab, listKeysService as ac, loginService as ad, logoutService as ae, oauthCallbackService as af, oauthNativeService as ag, oauthStartService as ah, oauthUnlinkNotifyService as ai, optionalAuth as aj, registerOAuthProvider as ak, registerPublicKeyService as al, registerService as am, requireEnabledProvider as an, resolveAuthenticatedUser as ao, revokeAllKeysService as ap, revokeKeyService as aq, rotateKeyService as ar, runAuthProfile as as, selectAuthProfile as at, sendVerificationCodeService as au, verifyCodeService as av, verifyOneTimeTokenService as aw, type RotateKeyResult as b, type RevokeAllKeysResult as c, type OAuthNativeResult as d, type ProfileInfo as e, type AuthSession as f, PERMISSION_CATEGORIES as g, type PermissionCategory as h, VERIFICATION_TARGET_TYPES as i, type VerificationPurpose as j, type VerificationTargetType as k, type OAuthProvider as l, mainAuthRouter as m, type AuthContext as n, type AuthProfileOutcome as o, type AuthProfileVerifier as p, KEY_FINGERPRINT_PREFIX_LENGTH as q, type LoginParams as r, type LogoutParams as s, type NormalizedIdentity as t, type OAuthCallbackParams as u, type OAuthCallbackResult as v, type OAuthCodeExchangeOptions as w, type OAuthNativeParams as x, type OAuthStartParams as y, type OAuthTokens as z };