@authn-sh/sdk-node 0.4.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,728 @@
1
+ export { AuthnApiError, AuthnConfigError, AuthnHttpError, AuthnTokenInvalidError, AuthnWebhookSignatureInvalidError } from './errors.js';
2
+
3
+ /**
4
+ * Pagination + ordering parameters shared by every `list*` BAPI call.
5
+ * Resource-specific filter params extend this with their own fields.
6
+ */
7
+ declare class ListParams {
8
+ limit?: number | undefined;
9
+ offset?: number | undefined;
10
+ orderBy?: string | undefined;
11
+ constructor(limit?: number | undefined, offset?: number | undefined, orderBy?: string | undefined);
12
+ toQuery(): Record<string, unknown>;
13
+ }
14
+
15
+ interface TransportOptions {
16
+ /** API base URL — typically `https://api.authn.sh/v1`. Trailing `/v1` is required. */
17
+ apiUrl: string;
18
+ /** Workspace-scoped secret key (`sk_test_…` / `sk_live_…`). */
19
+ secretKey: string;
20
+ /** Override the global fetch (e.g. for testing / proxying). */
21
+ fetch?: typeof fetch;
22
+ /** Default request timeout in milliseconds. Default 10_000. */
23
+ timeoutMs?: number;
24
+ /** User-Agent suffix, appended after `@authn-sh/sdk-node@<version>`. */
25
+ userAgentSuffix?: string;
26
+ }
27
+ interface RequestOptions {
28
+ /** Query parameters appended to the URL. Falsy values dropped. */
29
+ query?: Record<string, unknown>;
30
+ /** Body to send as JSON. */
31
+ body?: unknown;
32
+ /** Idempotency-Key header. */
33
+ idempotencyKey?: string;
34
+ /** Per-request timeout override. */
35
+ timeoutMs?: number;
36
+ /** Extra headers. Don't override Authorization / Content-Type. */
37
+ headers?: Record<string, string>;
38
+ }
39
+ /**
40
+ * Tiny fetch-based BAPI client. Bearer-authenticates with the workspace
41
+ * secret key, raises `AuthnHttpError` on non-2xx, returns parsed JSON
42
+ * on 2xx (or `null` on 204).
43
+ *
44
+ * Designed to run anywhere `fetch` exists: Node 18+, Edge runtimes,
45
+ * Cloudflare Workers, Vercel Edge, Bun, Deno.
46
+ */
47
+ declare class Transport {
48
+ private readonly apiUrl;
49
+ private readonly secretKey;
50
+ private readonly fetcher;
51
+ private readonly defaultTimeoutMs;
52
+ private readonly userAgent;
53
+ constructor(opts: TransportOptions);
54
+ /**
55
+ * Send a request and parse the response as JSON. For 204 returns `null`.
56
+ * Throws AuthnHttpError on non-2xx.
57
+ */
58
+ send<T = unknown>(method: string, path: string, opts?: RequestOptions): Promise<T>;
59
+ private buildUrl;
60
+ private extractApiErrors;
61
+ }
62
+
63
+ /**
64
+ * Base class for BAPI resource managers. Holds the shared Transport so
65
+ * subclasses can `.send()` without juggling auth themselves.
66
+ */
67
+ declare abstract class Manager {
68
+ protected readonly transport: Transport;
69
+ constructor(transport: Transport);
70
+ }
71
+
72
+ /**
73
+ * Generic paginated-list envelope returned by every `list*` BAPI endpoint.
74
+ */
75
+ interface PaginatedList<T> {
76
+ data: T[];
77
+ totalCount: number;
78
+ }
79
+
80
+ interface ExternalAccount {
81
+ id: string;
82
+ object: 'external_account';
83
+ provider: string;
84
+ providerKey: string;
85
+ providerUserId: string;
86
+ emailAddress?: string | null;
87
+ scopes: string[];
88
+ publicMetadata: Record<string, unknown>;
89
+ verified: boolean;
90
+ linkedAt?: number | null;
91
+ lastSignedInAt?: number | null;
92
+ raw: Record<string, unknown>;
93
+ }
94
+ declare class ExternalAccountsListParams extends ListParams {
95
+ userId?: string | undefined;
96
+ oauthProviderId?: string | undefined;
97
+ constructor(userId?: string | undefined, oauthProviderId?: string | undefined, limit?: number, offset?: number, orderBy?: string);
98
+ toQuery(): Record<string, unknown>;
99
+ }
100
+ declare class ExternalAccountsManager extends Manager {
101
+ list(params?: ExternalAccountsListParams): Promise<PaginatedList<ExternalAccount>>;
102
+ get(externalAccountId: string): Promise<ExternalAccount>;
103
+ delete(externalAccountId: string): Promise<void>;
104
+ }
105
+ declare function hydrateExternalAccount(raw: unknown): ExternalAccount;
106
+
107
+ interface InstanceSettings {
108
+ id: string;
109
+ object: 'instance';
110
+ attributes: Record<string, unknown>;
111
+ multiFactor: Record<string, unknown>;
112
+ signUpMode?: string;
113
+ raw: Record<string, unknown>;
114
+ }
115
+ declare class InstanceManager extends Manager {
116
+ get(): Promise<InstanceSettings>;
117
+ update(patch: Record<string, unknown>): Promise<InstanceSettings>;
118
+ updateRestrictions(patch: Record<string, unknown>): Promise<InstanceSettings>;
119
+ updateOrganizationSettings(patch: Record<string, unknown>): Promise<InstanceSettings>;
120
+ }
121
+ declare function hydrateInstance(raw: unknown): InstanceSettings;
122
+
123
+ interface Invitation {
124
+ id: string;
125
+ object: 'invitation';
126
+ emailAddress: string;
127
+ status: string;
128
+ redirectUrl?: string | null;
129
+ publicMetadata: Record<string, unknown>;
130
+ expiresAt?: number | null;
131
+ url?: string | null;
132
+ createdAt: number;
133
+ updatedAt: number;
134
+ raw: Record<string, unknown>;
135
+ }
136
+ declare class InvitationsListParams extends ListParams {
137
+ status?: string[] | undefined;
138
+ emailAddress?: string | undefined;
139
+ constructor(status?: string[] | undefined, emailAddress?: string | undefined, limit?: number, offset?: number, orderBy?: string);
140
+ toQuery(): Record<string, unknown>;
141
+ }
142
+ declare class InvitationsManager extends Manager {
143
+ list(params?: InvitationsListParams): Promise<PaginatedList<Invitation>>;
144
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<Invitation>;
145
+ bulkCreate(invitations: Array<Record<string, unknown>>, idempotencyKey?: string): Promise<Invitation[]>;
146
+ revoke(invitationId: string): Promise<Invitation>;
147
+ }
148
+ declare function hydrateInvitation(raw: unknown): Invitation;
149
+
150
+ interface AllowlistIdentifier {
151
+ id: string;
152
+ object: 'allowlist_identifier';
153
+ identifier: string;
154
+ createdAt: number;
155
+ updatedAt: number;
156
+ raw: Record<string, unknown>;
157
+ }
158
+ interface BlocklistIdentifier {
159
+ id: string;
160
+ object: 'blocklist_identifier';
161
+ identifier: string;
162
+ createdAt: number;
163
+ updatedAt: number;
164
+ raw: Record<string, unknown>;
165
+ }
166
+ declare class AllowlistIdentifiersManager extends Manager {
167
+ list(params?: ListParams): Promise<PaginatedList<AllowlistIdentifier>>;
168
+ create(data: {
169
+ identifier: string;
170
+ }): Promise<AllowlistIdentifier>;
171
+ delete(id: string): Promise<void>;
172
+ }
173
+ declare class BlocklistIdentifiersManager extends Manager {
174
+ list(params?: ListParams): Promise<PaginatedList<BlocklistIdentifier>>;
175
+ create(data: {
176
+ identifier: string;
177
+ }): Promise<BlocklistIdentifier>;
178
+ delete(id: string): Promise<void>;
179
+ }
180
+ declare function hydrateAllowlistIdentifier(raw: unknown): AllowlistIdentifier;
181
+ declare function hydrateBlocklistIdentifier(raw: unknown): BlocklistIdentifier;
182
+
183
+ interface OauthProvider {
184
+ id: string;
185
+ object: 'oauth_provider';
186
+ providerKind: 'preset' | 'custom_oidc' | 'custom_oauth2';
187
+ providerKey: string;
188
+ name: string;
189
+ enabled: boolean;
190
+ allowSignIn: boolean;
191
+ allowSignUp: boolean;
192
+ blockEmailSubaddresses: boolean;
193
+ clientId: string;
194
+ scopes: string[];
195
+ additionalAuthorizationParams: Record<string, unknown>;
196
+ attributeMapping: Record<string, string>;
197
+ redirectUri: string;
198
+ issuer?: string | null;
199
+ discoveryEndpoint?: string | null;
200
+ authorizationEndpoint?: string | null;
201
+ tokenEndpoint?: string | null;
202
+ userinfoEndpoint?: string | null;
203
+ jwksUri?: string | null;
204
+ idTokenSigningAlgs: string[];
205
+ userinfoMethod?: 'GET' | 'POST' | null;
206
+ userinfoAuth?: 'bearer' | 'basic' | 'query' | null;
207
+ createdAt: number;
208
+ updatedAt: number;
209
+ raw: Record<string, unknown>;
210
+ }
211
+ interface OauthProviderTestResult {
212
+ authorizeUrl: string;
213
+ userinfoStatus: number | null;
214
+ errors: Array<{
215
+ code: string;
216
+ message: string;
217
+ }>;
218
+ }
219
+ declare class OauthProvidersManager extends Manager {
220
+ list(params?: ListParams): Promise<PaginatedList<OauthProvider>>;
221
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<OauthProvider>;
222
+ get(oauthProviderId: string): Promise<OauthProvider>;
223
+ update(oauthProviderId: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<OauthProvider>;
224
+ delete(oauthProviderId: string): Promise<void>;
225
+ test(oauthProviderId: string): Promise<OauthProviderTestResult>;
226
+ }
227
+ declare function hydrateOauthProvider(raw: unknown): OauthProvider;
228
+
229
+ interface Organization {
230
+ id: string;
231
+ object: 'organization';
232
+ name: string;
233
+ slug?: string | null;
234
+ imageUrl?: string | null;
235
+ membersCount: number;
236
+ pendingInvitationsCount: number;
237
+ maxAllowedMemberships?: number | null;
238
+ adminDeleteEnabled: boolean;
239
+ publicMetadata: Record<string, unknown>;
240
+ privateMetadata: Record<string, unknown>;
241
+ createdBy?: string | null;
242
+ createdAt: number;
243
+ updatedAt: number;
244
+ raw: Record<string, unknown>;
245
+ }
246
+ interface OrganizationMembership {
247
+ id: string;
248
+ object: 'organization_membership';
249
+ organizationId: string;
250
+ userId: string;
251
+ role: string;
252
+ permissions: string[];
253
+ publicMetadata: Record<string, unknown>;
254
+ privateMetadata: Record<string, unknown>;
255
+ createdAt: number;
256
+ updatedAt: number;
257
+ raw: Record<string, unknown>;
258
+ }
259
+ interface OrganizationInvitation {
260
+ id: string;
261
+ object: 'organization_invitation';
262
+ organizationId: string;
263
+ emailAddress: string;
264
+ role: string;
265
+ status: string;
266
+ inviterUserId?: string | null;
267
+ redirectUrl?: string | null;
268
+ publicMetadata: Record<string, unknown>;
269
+ expiresAt?: number | null;
270
+ url?: string | null;
271
+ createdAt: number;
272
+ updatedAt: number;
273
+ raw: Record<string, unknown>;
274
+ }
275
+ interface OrganizationDomain {
276
+ id: string;
277
+ object: 'organization_domain';
278
+ organizationId: string;
279
+ name: string;
280
+ verified: boolean;
281
+ enrollmentMode: string;
282
+ currentChallengeId?: string | null;
283
+ createdAt: number;
284
+ updatedAt: number;
285
+ raw: Record<string, unknown>;
286
+ }
287
+ declare class OrganizationsManager extends Manager {
288
+ list(params?: ListParams): Promise<PaginatedList<Organization>>;
289
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<Organization>;
290
+ get(orgId: string): Promise<Organization>;
291
+ update(orgId: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<Organization>;
292
+ delete(orgId: string): Promise<void>;
293
+ members(orgId: string): OrganizationMembershipsManager;
294
+ invitations(orgId: string): OrganizationInvitationsManager;
295
+ domains(orgId: string): OrganizationDomainsManager;
296
+ }
297
+ declare class OrganizationMembershipsManager {
298
+ private readonly transport;
299
+ private readonly orgId;
300
+ constructor(transport: Transport, orgId: string);
301
+ list(params?: ListParams): Promise<PaginatedList<OrganizationMembership>>;
302
+ create(data: {
303
+ userId: string;
304
+ role: string;
305
+ }, idempotencyKey?: string): Promise<OrganizationMembership>;
306
+ update(userId: string, role: string, idempotencyKey?: string): Promise<OrganizationMembership>;
307
+ delete(userId: string): Promise<void>;
308
+ }
309
+ declare class OrganizationInvitationsManager {
310
+ private readonly transport;
311
+ private readonly orgId;
312
+ constructor(transport: Transport, orgId: string);
313
+ list(params?: ListParams): Promise<PaginatedList<OrganizationInvitation>>;
314
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<OrganizationInvitation>;
315
+ bulkCreate(invitations: Array<Record<string, unknown>>, idempotencyKey?: string): Promise<OrganizationInvitation[]>;
316
+ revoke(invitationId: string): Promise<OrganizationInvitation>;
317
+ }
318
+ declare class OrganizationDomainsManager {
319
+ private readonly transport;
320
+ private readonly orgId;
321
+ constructor(transport: Transport, orgId: string);
322
+ list(): Promise<PaginatedList<OrganizationDomain>>;
323
+ create(name: string, enrollmentMode?: string): Promise<OrganizationDomain>;
324
+ get(domainId: string): Promise<OrganizationDomain>;
325
+ update(domainId: string, patch: Record<string, unknown>): Promise<OrganizationDomain>;
326
+ delete(domainId: string): Promise<void>;
327
+ }
328
+ declare function hydrateOrganization(raw: unknown): Organization;
329
+ declare function hydrateOrganizationMembership(raw: unknown): OrganizationMembership;
330
+ declare function hydrateOrganizationInvitation(raw: unknown): OrganizationInvitation;
331
+ declare function hydrateOrganizationDomain(raw: unknown): OrganizationDomain;
332
+
333
+ interface PhoneNumber {
334
+ id: string;
335
+ object: 'phone_number';
336
+ phoneNumber: string;
337
+ verified: boolean;
338
+ currentChallengeId?: string | null;
339
+ isPrimary: boolean;
340
+ reservedForSecondFactor: boolean;
341
+ defaultSecondFactor: boolean;
342
+ linkedToExternalAccountId?: string | null;
343
+ createdAt: number;
344
+ updatedAt: number;
345
+ raw: Record<string, unknown>;
346
+ }
347
+ declare class PhoneNumbersListParams extends ListParams {
348
+ userId?: string | undefined;
349
+ constructor(userId?: string | undefined, limit?: number, offset?: number, orderBy?: string);
350
+ toQuery(): Record<string, unknown>;
351
+ }
352
+ declare class PhoneNumbersManager extends Manager {
353
+ list(params?: PhoneNumbersListParams): Promise<PaginatedList<PhoneNumber>>;
354
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<PhoneNumber>;
355
+ get(phoneNumberId: string): Promise<PhoneNumber>;
356
+ update(phoneNumberId: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<PhoneNumber>;
357
+ delete(phoneNumberId: string): Promise<void>;
358
+ }
359
+ declare function hydratePhoneNumber(raw: unknown): PhoneNumber;
360
+
361
+ interface RedirectUrl {
362
+ id: string;
363
+ object: 'redirect_url';
364
+ url: string;
365
+ createdAt: number;
366
+ updatedAt: number;
367
+ raw: Record<string, unknown>;
368
+ }
369
+ declare class RedirectUrlsManager extends Manager {
370
+ list(params?: ListParams): Promise<PaginatedList<RedirectUrl>>;
371
+ create(url: string): Promise<RedirectUrl>;
372
+ get(id: string): Promise<RedirectUrl>;
373
+ delete(id: string): Promise<void>;
374
+ }
375
+ declare function hydrateRedirectUrl(raw: unknown): RedirectUrl;
376
+
377
+ interface Role {
378
+ id: string;
379
+ object: 'role';
380
+ key: string;
381
+ name: string;
382
+ description?: string | null;
383
+ isCreatorEligible: boolean;
384
+ isDefault: boolean;
385
+ permissions: string[];
386
+ createdAt: number;
387
+ updatedAt: number;
388
+ raw: Record<string, unknown>;
389
+ }
390
+ interface Permission {
391
+ id: string;
392
+ object: 'permission';
393
+ key: string;
394
+ name: string;
395
+ description?: string | null;
396
+ isSystem: boolean;
397
+ createdAt: number;
398
+ updatedAt: number;
399
+ raw: Record<string, unknown>;
400
+ }
401
+ declare class RolesManager extends Manager {
402
+ list(params?: ListParams): Promise<PaginatedList<Role>>;
403
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<Role>;
404
+ get(roleId: string): Promise<Role>;
405
+ update(roleId: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<Role>;
406
+ delete(roleId: string): Promise<void>;
407
+ setPermissions(roleId: string, permissionKeys: string[]): Promise<Role>;
408
+ }
409
+ declare class PermissionsManager extends Manager {
410
+ list(params?: ListParams): Promise<PaginatedList<Permission>>;
411
+ }
412
+ declare function hydrateRole(raw: unknown): Role;
413
+ declare function hydratePermission(raw: unknown): Permission;
414
+
415
+ interface Session {
416
+ id: string;
417
+ object: 'session';
418
+ clientId: string;
419
+ userId: string;
420
+ status: string;
421
+ lastActiveAt?: number | null;
422
+ expireAt?: number | null;
423
+ abandonAt?: number | null;
424
+ lastActiveOrganizationId?: string | null;
425
+ createdAt: number;
426
+ updatedAt: number;
427
+ raw: Record<string, unknown>;
428
+ }
429
+ declare class SessionsListParams extends ListParams {
430
+ userId?: string | undefined;
431
+ clientId?: string | undefined;
432
+ status?: string[] | undefined;
433
+ constructor(userId?: string | undefined, clientId?: string | undefined, status?: string[] | undefined, limit?: number, offset?: number, orderBy?: string);
434
+ toQuery(): Record<string, unknown>;
435
+ }
436
+ declare class SessionsManager extends Manager {
437
+ list(params?: SessionsListParams): Promise<PaginatedList<Session>>;
438
+ get(sessionId: string): Promise<Session>;
439
+ revoke(sessionId: string): Promise<Session>;
440
+ getToken(sessionId: string, template?: string): Promise<string>;
441
+ }
442
+ declare function hydrateSession(raw: unknown): Session;
443
+
444
+ type SmsTemplateSlug = 'verification_code' | 'reset_password_code' | 'invitation';
445
+ interface SmsTemplate {
446
+ id: string;
447
+ object: 'sms_template';
448
+ slug: SmsTemplateSlug | string;
449
+ body: string;
450
+ deliveredByUs: boolean;
451
+ fromNumberOverride?: string | null;
452
+ createdAt: number;
453
+ updatedAt: number;
454
+ raw: Record<string, unknown>;
455
+ }
456
+ declare class SmsTemplatesManager extends Manager {
457
+ list(): Promise<SmsTemplate[]>;
458
+ get(slug: string): Promise<SmsTemplate>;
459
+ update(slug: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<SmsTemplate>;
460
+ revert(slug: string, idempotencyKey?: string): Promise<SmsTemplate>;
461
+ }
462
+ declare function hydrateSmsTemplate(raw: unknown): SmsTemplate;
463
+
464
+ interface User {
465
+ id: string;
466
+ object: 'user';
467
+ externalId?: string | null;
468
+ username?: string | null;
469
+ firstName?: string | null;
470
+ lastName?: string | null;
471
+ imageUrl?: string | null;
472
+ primaryEmailAddressId?: string | null;
473
+ primaryPhoneNumberId?: string | null;
474
+ emailAddresses: Array<Record<string, unknown>>;
475
+ phoneNumbers: Array<Record<string, unknown>>;
476
+ externalAccounts: Array<Record<string, unknown>>;
477
+ passwordEnabled: boolean;
478
+ totpEnabled: boolean;
479
+ backupCodesEnabled: boolean;
480
+ twoFactorEnabled: boolean;
481
+ banned: boolean;
482
+ locked: boolean;
483
+ lastSignInAt?: number | null;
484
+ lastActiveAt?: number | null;
485
+ publicMetadata: Record<string, unknown>;
486
+ privateMetadata: Record<string, unknown>;
487
+ unsafeMetadata: Record<string, unknown>;
488
+ createdAt: number;
489
+ updatedAt: number;
490
+ raw: Record<string, unknown>;
491
+ }
492
+ interface TotpVerificationResult {
493
+ verified: boolean;
494
+ reason?: string | null;
495
+ }
496
+ declare class UsersListParams extends ListParams {
497
+ emailAddress?: string[] | undefined;
498
+ phoneNumber?: string[] | undefined;
499
+ username?: string[] | undefined;
500
+ externalId?: string[] | undefined;
501
+ query?: string | undefined;
502
+ constructor(emailAddress?: string[] | undefined, phoneNumber?: string[] | undefined, username?: string[] | undefined, externalId?: string[] | undefined, query?: string | undefined, limit?: number, offset?: number, orderBy?: string);
503
+ toQuery(): Record<string, unknown>;
504
+ }
505
+ declare class UsersManager extends Manager {
506
+ list(params?: UsersListParams): Promise<PaginatedList<User>>;
507
+ count(params?: UsersListParams): Promise<number>;
508
+ create(data: Record<string, unknown>, idempotencyKey?: string): Promise<User>;
509
+ get(userId: string): Promise<User>;
510
+ update(userId: string, data: Record<string, unknown>, idempotencyKey?: string): Promise<User>;
511
+ delete(userId: string): Promise<void>;
512
+ ban(userId: string): Promise<User>;
513
+ unban(userId: string): Promise<User>;
514
+ lock(userId: string): Promise<User>;
515
+ unlock(userId: string): Promise<User>;
516
+ updateMetadata(userId: string, patch: Record<string, unknown>): Promise<User>;
517
+ verifyPassword(userId: string, password: string): Promise<boolean>;
518
+ verifyTotp(userId: string, code: string): Promise<TotpVerificationResult>;
519
+ disableMfa(userId: string): Promise<User>;
520
+ uploadProfileImage(userId: string, bytes: Uint8Array, mime: string): Promise<User>;
521
+ deleteProfileImage(userId: string): Promise<void>;
522
+ }
523
+ declare function hydrateUser(raw: unknown): User;
524
+
525
+ interface AuthnOptions {
526
+ /** Workspace-scoped secret key — `sk_test_…` / `sk_live_…`. */
527
+ secretKey: string;
528
+ /** BAPI base URL (host only, no `/v1` — manager paths include it). Default `https://api.authn.sh`. */
529
+ apiUrl?: string;
530
+ /** Override the global fetch (testing / proxying). */
531
+ fetch?: typeof fetch;
532
+ /** Request timeout in milliseconds. Default 10_000. */
533
+ timeoutMs?: number;
534
+ /** User-Agent suffix, appended after `@authn-sh/sdk-node`. */
535
+ userAgentSuffix?: string;
536
+ }
537
+ /**
538
+ * BAPI client for authn.sh. Single entry point — instantiate once,
539
+ * reuse across requests.
540
+ *
541
+ * @example
542
+ * const authn = new Authn({ secretKey: process.env.AUTHN_SECRET_KEY! });
543
+ * const user = await authn.users.get('user_01HXYZ...');
544
+ * const session = await authn.sessions.get(req.cookies.authnSessionId);
545
+ */
546
+ declare class Authn {
547
+ /** Underlying HTTP transport — exposed for advanced use cases. */
548
+ readonly transport: Transport;
549
+ readonly users: UsersManager;
550
+ readonly sessions: SessionsManager;
551
+ readonly organizations: OrganizationsManager;
552
+ readonly oauthProviders: OauthProvidersManager;
553
+ readonly phoneNumbers: PhoneNumbersManager;
554
+ readonly externalAccounts: ExternalAccountsManager;
555
+ readonly smsTemplates: SmsTemplatesManager;
556
+ readonly invitations: InvitationsManager;
557
+ readonly allowlistIdentifiers: AllowlistIdentifiersManager;
558
+ readonly blocklistIdentifiers: BlocklistIdentifiersManager;
559
+ readonly redirectUrls: RedirectUrlsManager;
560
+ readonly roles: RolesManager;
561
+ readonly permissions: PermissionsManager;
562
+ readonly instance: InstanceManager;
563
+ constructor(opts: AuthnOptions);
564
+ }
565
+
566
+ interface VerifiedOrganization {
567
+ id: string;
568
+ slug?: string;
569
+ role?: string;
570
+ permissions: string[];
571
+ }
572
+ interface VerifiedActor {
573
+ iss: string;
574
+ sub: string;
575
+ sid: string;
576
+ }
577
+ /**
578
+ * Strongly-typed view of a verified session-JWT's claims.
579
+ *
580
+ * Use the helper methods (`hasRole`, `hasPermission`,
581
+ * `hasVerifiedPhoneNumber`, `preferredSecondFactor`) rather than poking
582
+ * into `raw` directly — the helpers are the stable surface, raw fields
583
+ * may change shape.
584
+ */
585
+ declare class VerifiedClaims {
586
+ readonly sub: string;
587
+ readonly sid: string;
588
+ readonly iss: string;
589
+ readonly azp: string | null;
590
+ readonly exp: number;
591
+ readonly iat: number;
592
+ readonly nbf: number | null;
593
+ readonly actor: VerifiedActor | null;
594
+ readonly organization: VerifiedOrganization | null;
595
+ readonly wasTest: boolean;
596
+ readonly twoFactorVerified: boolean;
597
+ readonly secondFactorAgeSeconds: number | null;
598
+ readonly firstFactorAgeSeconds: number | null;
599
+ readonly phoneNumberVerified: boolean;
600
+ readonly defaultSecondFactor: 'totp' | 'phone_code' | 'backup_code' | null;
601
+ readonly raw: Record<string, unknown>;
602
+ constructor(sub: string, sid: string, iss: string, azp: string | null, exp: number, iat: number, nbf: number | null, actor: VerifiedActor | null, organization: VerifiedOrganization | null, wasTest: boolean, twoFactorVerified: boolean, secondFactorAgeSeconds: number | null, firstFactorAgeSeconds: number | null, phoneNumberVerified: boolean, defaultSecondFactor: 'totp' | 'phone_code' | 'backup_code' | null, raw: Record<string, unknown>);
603
+ hasRole(roleKey: string): boolean;
604
+ hasPermission(permissionKey: string): boolean;
605
+ hasVerifiedPhoneNumber(): boolean;
606
+ preferredSecondFactor(): VerifiedClaims['defaultSecondFactor'];
607
+ }
608
+ /**
609
+ * Build a VerifiedClaims from a JWT claims-bag (post-signature-verify).
610
+ */
611
+ declare function buildVerifiedClaims(claims: Record<string, unknown>): VerifiedClaims;
612
+
613
+ interface TokenVerifierOptions {
614
+ /**
615
+ * Workspace publishable key (`pk_test_…` / `pk_live_…`). The verifier
616
+ * decodes the FAPI host from the key, e.g. `pk_test_<env_slug>` →
617
+ * `https://<env_slug>.authn.sh`.
618
+ */
619
+ publishableKey?: string;
620
+ /**
621
+ * Explicit FAPI base URL (`https://<env_slug>.authn.sh`). Use this
622
+ * when self-hosting on a custom domain — overrides `publishableKey`
623
+ * decoding.
624
+ */
625
+ frontendApiUrl?: string;
626
+ /** JWKS cache TTL in seconds. Default 600. */
627
+ jwksCacheTtlSeconds?: number;
628
+ /** Allowed clock skew on exp/nbf validation in seconds. Default 5. */
629
+ allowedClockSkewSeconds?: number;
630
+ /** Override the global fetch (testing). */
631
+ fetch?: typeof fetch;
632
+ }
633
+ /**
634
+ * Verifies session JWTs minted by an authn.sh Frontend API.
635
+ *
636
+ * Resolves the FAPI's JWKS URL from `publishableKey` or `frontendApiUrl`,
637
+ * caches it in memory, and validates the signature + expiry + issuer.
638
+ *
639
+ * @example
640
+ * const verifier = new TokenVerifier({ publishableKey: process.env.AUTHN_PUBLISHABLE_KEY! });
641
+ * const claims = await verifier.verify(req.cookies.__session);
642
+ * console.log(claims.sub); // user_…
643
+ * console.log(claims.hasPermission('org:billing:read'));
644
+ * console.log(claims.preferredSecondFactor()); // 'totp' | 'phone_code' | 'backup_code' | null
645
+ */
646
+ declare class TokenVerifier {
647
+ private readonly frontendApiUrl;
648
+ private readonly jwks;
649
+ private readonly allowedClockSkew;
650
+ constructor(opts?: TokenVerifierOptions);
651
+ /**
652
+ * Verify a JWT and return its claims. Throws AuthnTokenInvalidError on failure.
653
+ *
654
+ * @param expectedAzp If provided, the token's `azp` must match one of these.
655
+ */
656
+ verify(jwt: string, expectedAzp?: string[]): Promise<VerifiedClaims>;
657
+ /**
658
+ * Same as `verify` but returns `null` on failure instead of throwing.
659
+ * Useful for "best-effort" auth that falls back to unauthenticated.
660
+ */
661
+ tryVerify(jwt: string, expectedAzp?: string[]): Promise<VerifiedClaims | null>;
662
+ }
663
+ /**
664
+ * Decode the FAPI URL embedded in a publishable key.
665
+ *
666
+ * Publishable keys look like `pk_(test|live)_<base64url-encoded-host>$`.
667
+ * The host segment is `<env_slug>.authn.sh` (no scheme). We always
668
+ * emit `https://`.
669
+ */
670
+ declare function decodeFrontendApiUrl(publishableKey: string): string;
671
+
672
+ interface WebhookEvent {
673
+ /** Event type (`user.created`, `phoneNumber.verified`, etc.). */
674
+ type: string;
675
+ /** Event payload. Resource shape — depends on `type`. */
676
+ data: Record<string, unknown>;
677
+ /** Unix timestamp (seconds) when the event was emitted. */
678
+ timestamp: number;
679
+ /** Instance ID the event was emitted from. */
680
+ instanceId: string;
681
+ /** Whether the event was generated during a test-mode flow. */
682
+ wasTest: boolean;
683
+ /** Message ID (the `svix-id` header value). */
684
+ messageId: string;
685
+ }
686
+
687
+ interface WebhookSignatureVerifierOptions {
688
+ /**
689
+ * `whsec_…` signing secret. Pass an array to tolerate key rotation —
690
+ * a request is accepted if any provided signature matches any secret.
691
+ */
692
+ signingSecret: string | string[];
693
+ /** Acceptable clock skew window in seconds. Default 300 (5 min). */
694
+ toleranceSeconds?: number;
695
+ /** Override the clock (testing). Returns unix seconds. */
696
+ now?: () => number;
697
+ }
698
+ /**
699
+ * Verifies authn.sh webhook signatures (svix-compatible scheme).
700
+ *
701
+ * The transport signs `{svix-id}.{svix-timestamp}.{rawBody}` with
702
+ * HMAC-SHA256 keyed by `whsec_…`. Multiple secrets can be supplied to
703
+ * tolerate rotation — a request is accepted if any provided signature
704
+ * matches any configured secret.
705
+ *
706
+ * @example
707
+ * app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
708
+ * const verifier = new WebhookSignatureVerifier({ signingSecret: process.env.AUTHN_WEBHOOK_SECRET! });
709
+ * try {
710
+ * const event = verifier.verify(req.body.toString('utf8'), req.headers);
711
+ * // event.type === 'user.created' | 'phoneNumber.verified' | ...
712
+ * } catch (e) {
713
+ * return res.status(400).end();
714
+ * }
715
+ * res.status(204).end();
716
+ * });
717
+ */
718
+ declare class WebhookSignatureVerifier {
719
+ private readonly secrets;
720
+ private readonly tolerance;
721
+ private readonly now;
722
+ constructor(opts: WebhookSignatureVerifierOptions);
723
+ verify(rawBody: string, headers: Record<string, string | string[] | undefined>): WebhookEvent;
724
+ tryVerify(rawBody: string, headers: Record<string, string | string[] | undefined>): WebhookEvent | null;
725
+ private matchesAny;
726
+ }
727
+
728
+ export { type AllowlistIdentifier, AllowlistIdentifiersManager, Authn, type AuthnOptions, type BlocklistIdentifier, BlocklistIdentifiersManager, type ExternalAccount, ExternalAccountsListParams, ExternalAccountsManager, InstanceManager, type InstanceSettings, type Invitation, InvitationsListParams, InvitationsManager, ListParams, type OauthProvider, type OauthProviderTestResult, OauthProvidersManager, type Organization, type OrganizationDomain, OrganizationDomainsManager, type OrganizationInvitation, OrganizationInvitationsManager, type OrganizationMembership, OrganizationMembershipsManager, OrganizationsManager, type PaginatedList, type Permission, PermissionsManager, type PhoneNumber, PhoneNumbersListParams, PhoneNumbersManager, type RedirectUrl, RedirectUrlsManager, type RequestOptions, type Role, RolesManager, type Session, SessionsListParams, SessionsManager, type SmsTemplate, type SmsTemplateSlug, SmsTemplatesManager, TokenVerifier, type TokenVerifierOptions, type TotpVerificationResult, Transport, type TransportOptions, type User, UsersListParams, UsersManager, type VerifiedActor, VerifiedClaims, type VerifiedOrganization, type WebhookEvent, WebhookSignatureVerifier, type WebhookSignatureVerifierOptions, buildVerifiedClaims, decodeFrontendApiUrl, hydrateAllowlistIdentifier, hydrateBlocklistIdentifier, hydrateExternalAccount, hydrateInstance, hydrateInvitation, hydrateOauthProvider, hydrateOrganization, hydrateOrganizationDomain, hydrateOrganizationInvitation, hydrateOrganizationMembership, hydratePermission, hydratePhoneNumber, hydrateRedirectUrl, hydrateRole, hydrateSession, hydrateSmsTemplate, hydrateUser };