@spfn/auth 0.3.0-beta.23 → 0.3.0-beta.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -2
- package/dist/client-proof.js +13 -5
- package/dist/client-proof.js.map +1 -1
- package/dist/client.d.ts +52 -1
- package/dist/client.js +40 -0
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +82 -0
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +1 -1
- package/dist/errors.d.ts +113 -3
- package/dist/errors.js +68 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +38 -5
- package/dist/index.js +73 -2
- package/dist/index.js.map +1 -1
- package/dist/{machine-principals-CaEFq61K.d.ts → machine-principals-ZJd9anVT.d.ts} +1667 -900
- package/dist/nextjs/api.js +156 -6
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.d.ts +42 -24
- package/dist/nextjs/server.js +72 -5
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +448 -525
- package/dist/server.js +1389 -653
- package/dist/server.js.map +1 -1
- package/dist/{session-Dfwu5g2W.d.ts → session-BbhAGZtA.d.ts} +57 -1
- package/dist/{types-DYyhze28.d.ts → types-CTdoTOxM.d.ts} +24 -1
- package/migrations/20260918184037_happy_mordo/migration.sql +4 -0
- package/migrations/20260918184037_happy_mordo/snapshot.json +6000 -0
- package/migrations/20260918184152_dear_rictor/migration.sql +3 -0
- package/migrations/20260918184152_dear_rictor/snapshot.json +6039 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as _spfn_core_nextjs from '@spfn/core/nextjs';
|
|
2
|
-
import { P as PermissionConfig, R as RoleConfig, m as mainAuthRouter, S as SendVerificationCodeResult, a as RegisterResult, b as RequestSignupLinkResult, C as ConfirmSignupLinkResult, c as RequestPasswordResetResult, d as ConfirmPasswordResetResult, L as
|
|
3
|
-
export { A as AuthInitOptions,
|
|
2
|
+
import { P as PermissionConfig, R as RoleConfig, m as mainAuthRouter, S as SendVerificationCodeResult, a as RegisterResult, b as RequestSignupLinkResult, C as ConfirmSignupLinkResult, c as RequestPasswordResetResult, d as ConfirmPasswordResetResult, L as LoginBindingFields, e as LoginResult, f as StartDeviceAuthResult, D as DeviceAuthInfoResult, F as FinishPasskeyEnrollmentResult, g as PasskeySummary, T as TotpEnrolmentResult, h as ConfirmTotpResult, M as MfaStatus, i as RotateKeyResult, K as KeySummary, j as RevokeAllKeysResult, k as SessionBindingResult, l as SessionRenewResult, I as IssueOneTimeTokenResult, O as OAuthStartResult, n as OAuthNativeResult, U as UserProfile, o as ProfileInfo, p as OAuth2ConsentView, q as OAuth2AuthorizationCodeIssued, r as OAuth2GrantSummary } from './machine-principals-ZJd9anVT.js';
|
|
3
|
+
export { A as AuthInitOptions, s as AuthSession, t as PERMISSION_CATEGORIES, u as PermissionCategory, V as VERIFICATION_PURPOSES, v as VERIFICATION_TARGET_TYPES, w as VerificationPurpose, x as VerificationTargetType } from './machine-principals-ZJd9anVT.js';
|
|
4
4
|
import * as _simplewebauthn_server from '@simplewebauthn/server';
|
|
5
5
|
import * as _spfn_core_route from '@spfn/core/route';
|
|
6
6
|
import { HttpMethod } from '@spfn/core/route';
|
|
7
|
-
|
|
7
|
+
import { S as SessionBindingType } from './types-CTdoTOxM.js';
|
|
8
|
+
export { A as ACCOUNT_DELETION_REQUESTED_BY, a as ACCOUNT_DELETION_REQUEST_STATUSES, b as AccountDeletionRequestStatus, c as AccountDeletionRequestedBy, I as INVITATION_STATUSES, d as InvitationStatus, e as KEY_ALGORITHM, f as KEY_DEVICE_NAME_MAX_LENGTH, g as KEY_PLATFORM, K as KeyAlgorithmType, h as KeyPlatformType, P as PURGE_STRATEGIES, i as PurgeStrategy, j as SESSION_BINDINGS, k as SOCIAL_PROVIDERS, l as SocialProvider, U as USER_STATUSES, m as UserStatus } from './types-CTdoTOxM.js';
|
|
8
9
|
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
9
10
|
import 'drizzle-orm/pg-core';
|
|
10
11
|
import '@spfn/core/event';
|
|
@@ -180,7 +181,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
180
181
|
deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
181
182
|
platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
|
|
182
183
|
}>;
|
|
183
|
-
}, RegisterResult>;
|
|
184
|
+
}, RegisterResult & LoginBindingFields>;
|
|
184
185
|
login: _spfn_core_route.RouteDef<{
|
|
185
186
|
body: _sinclair_typebox.TObject<{
|
|
186
187
|
email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
@@ -218,6 +219,8 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
218
219
|
} | {
|
|
219
220
|
email?: string | undefined;
|
|
220
221
|
phone?: string | undefined;
|
|
222
|
+
sessionBinding?: "none" | "passkey" | undefined;
|
|
223
|
+
keyExpiresAtMillis?: number | undefined;
|
|
221
224
|
status: "approved";
|
|
222
225
|
userId: string;
|
|
223
226
|
publicId: string;
|
|
@@ -394,6 +397,32 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
394
397
|
phoneVerified: boolean;
|
|
395
398
|
hasPassword: boolean;
|
|
396
399
|
}>;
|
|
400
|
+
setSessionBinding: _spfn_core_route.RouteDef<{
|
|
401
|
+
body: _sinclair_typebox.TObject<{
|
|
402
|
+
mode: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"passkey">, _sinclair_typebox.TLiteral<"none">]>;
|
|
403
|
+
response: _sinclair_typebox.TOptional<_sinclair_typebox.TUnknown>;
|
|
404
|
+
currentPassword: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
405
|
+
}>;
|
|
406
|
+
}, {}, SessionBindingResult>;
|
|
407
|
+
getSessionBinding: _spfn_core_route.RouteDef<{}, {}, SessionBindingResult>;
|
|
408
|
+
sessionBindingDisableOptions: _spfn_core_route.RouteDef<{
|
|
409
|
+
body: _sinclair_typebox.TObject<{}>;
|
|
410
|
+
}, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
|
|
411
|
+
sessionRenewOptions: _spfn_core_route.RouteDef<{
|
|
412
|
+
body: _sinclair_typebox.TObject<{}>;
|
|
413
|
+
}, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
|
|
414
|
+
sessionRenewVerify: _spfn_core_route.RouteDef<{
|
|
415
|
+
body: _sinclair_typebox.TObject<{
|
|
416
|
+
response: _sinclair_typebox.TUnknown;
|
|
417
|
+
}>;
|
|
418
|
+
}, {
|
|
419
|
+
body: _sinclair_typebox.TObject<{
|
|
420
|
+
publicKey: _sinclair_typebox.TString;
|
|
421
|
+
keyId: _sinclair_typebox.TString;
|
|
422
|
+
fingerprint: _sinclair_typebox.TString;
|
|
423
|
+
algorithm: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>>;
|
|
424
|
+
}>;
|
|
425
|
+
}, SessionRenewResult>;
|
|
397
426
|
issueOneTimeToken: _spfn_core_route.RouteDef<{}, {}, IssueOneTimeTokenResult>;
|
|
398
427
|
requestAccountDeletion: _spfn_core_route.RouteDef<{
|
|
399
428
|
body: _sinclair_typebox.TObject<{
|
|
@@ -456,6 +485,8 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
456
485
|
returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
|
|
457
486
|
}>;
|
|
458
487
|
}, {}, {
|
|
488
|
+
sessionBinding?: SessionBindingType;
|
|
489
|
+
keyExpiresAtMillis?: number;
|
|
459
490
|
success: boolean;
|
|
460
491
|
userId: string;
|
|
461
492
|
keyId: string;
|
|
@@ -670,6 +701,8 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
670
701
|
emailVerifiedAt: Date | null;
|
|
671
702
|
phoneVerifiedAt: Date | null;
|
|
672
703
|
keyEpoch: number;
|
|
704
|
+
sessionBinding: "none" | "passkey";
|
|
705
|
+
sessionBindingChangedAt: Date | null;
|
|
673
706
|
lastLoginAt: Date | null;
|
|
674
707
|
}>;
|
|
675
708
|
updateLocale: _spfn_core_route.RouteDef<{
|
|
@@ -843,4 +876,4 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
|
|
|
843
876
|
}>>;
|
|
844
877
|
type AuthRouter = typeof mainAuthRouter;
|
|
845
878
|
|
|
846
|
-
export { type AuthRouter, BASE64_PATTERN, BUILTIN_PERMISSIONS, BUILTIN_ROLES, BUILTIN_ROLE_PERMISSIONS, type BuiltinPermissionName, type BuiltinRoleName, EMAIL_PATTERN, FINGERPRINT_PATTERN, PHONE_PATTERN, PermissionConfig, ProfileInfo, RoleConfig, UUID_PATTERN, UserProfile, authApi, routeMap as authRouteMap };
|
|
879
|
+
export { type AuthRouter, BASE64_PATTERN, BUILTIN_PERMISSIONS, BUILTIN_ROLES, BUILTIN_ROLE_PERMISSIONS, type BuiltinPermissionName, type BuiltinRoleName, EMAIL_PATTERN, FINGERPRINT_PATTERN, PHONE_PATTERN, PermissionConfig, ProfileInfo, RoleConfig, SessionBindingType, UUID_PATTERN, UserProfile, authApi, routeMap as authRouteMap };
|
package/dist/index.js
CHANGED
|
@@ -12,12 +12,14 @@ import { ErrorRegistry } from "@spfn/core/errors";
|
|
|
12
12
|
|
|
13
13
|
// src/errors/auth-errors.ts
|
|
14
14
|
import {
|
|
15
|
+
BadRequestError,
|
|
15
16
|
ValidationError,
|
|
16
17
|
UnauthorizedError,
|
|
17
18
|
ForbiddenError,
|
|
18
19
|
ConflictError,
|
|
19
20
|
NotFoundError,
|
|
20
|
-
HttpError
|
|
21
|
+
HttpError,
|
|
22
|
+
InternalServerError
|
|
21
23
|
} from "@spfn/core/errors";
|
|
22
24
|
var InvalidCredentialsError = class extends UnauthorizedError {
|
|
23
25
|
constructor(data = {}) {
|
|
@@ -366,6 +368,56 @@ var LastRecoveryCredentialError = class extends ConflictError {
|
|
|
366
368
|
this.name = "LastRecoveryCredentialError";
|
|
367
369
|
}
|
|
368
370
|
};
|
|
371
|
+
var SessionRenewalRequiredError = class extends UnauthorizedError {
|
|
372
|
+
code = "SESSION_RENEWAL_REQUIRED";
|
|
373
|
+
constructor(data = {}) {
|
|
374
|
+
super({
|
|
375
|
+
message: data.message || "This session needs renewing. Confirm with your passkey to continue.",
|
|
376
|
+
details: data.details
|
|
377
|
+
});
|
|
378
|
+
this.name = "SessionRenewalRequiredError";
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
var SessionRenewalRefusedError = class extends UnauthorizedError {
|
|
382
|
+
code = "SESSION_RENEWAL_REFUSED";
|
|
383
|
+
constructor(data = {}) {
|
|
384
|
+
super({
|
|
385
|
+
message: data.message || "This session cannot be renewed. Sign in again.",
|
|
386
|
+
details: data.details
|
|
387
|
+
});
|
|
388
|
+
this.name = "SessionRenewalRefusedError";
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
var SessionContextChangedError = class extends UnauthorizedError {
|
|
392
|
+
code = "SESSION_CONTEXT_CHANGED";
|
|
393
|
+
constructor(data = {}) {
|
|
394
|
+
super({
|
|
395
|
+
message: data.message || "This session was started in a different browser. Sign in again.",
|
|
396
|
+
details: data.details
|
|
397
|
+
});
|
|
398
|
+
this.name = "SessionContextChangedError";
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var SessionBindingUnavailableError = class extends BadRequestError {
|
|
402
|
+
code = "SESSION_BINDING_UNAVAILABLE";
|
|
403
|
+
constructor(data = {}) {
|
|
404
|
+
super({
|
|
405
|
+
message: data.message || "Session binding needs a deployment where the backend can recognise the Next.js proxy. Configure proxy-guard (SPFN_PROXY_SIGNATURE_KEYS) and try again.",
|
|
406
|
+
details: data.details
|
|
407
|
+
});
|
|
408
|
+
this.name = "SessionBindingUnavailableError";
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
var SessionResealFailedError = class extends InternalServerError {
|
|
412
|
+
code = "SESSION_RESEAL_FAILED";
|
|
413
|
+
constructor(data = {}) {
|
|
414
|
+
super({
|
|
415
|
+
message: data.message || "The setting was changed but this session could not be updated. Sign in again.",
|
|
416
|
+
details: data.details
|
|
417
|
+
});
|
|
418
|
+
this.name = "SessionResealFailedError";
|
|
419
|
+
}
|
|
420
|
+
};
|
|
369
421
|
var PasskeyConfigError = class extends HttpError {
|
|
370
422
|
constructor(data) {
|
|
371
423
|
super({
|
|
@@ -508,6 +560,11 @@ authErrorRegistry.append([
|
|
|
508
560
|
RecentAuthenticationRequiredError,
|
|
509
561
|
LastRecoveryCredentialError,
|
|
510
562
|
PasskeyConfigError,
|
|
563
|
+
SessionBindingUnavailableError,
|
|
564
|
+
SessionRenewalRequiredError,
|
|
565
|
+
SessionRenewalRefusedError,
|
|
566
|
+
SessionContextChangedError,
|
|
567
|
+
SessionResealFailedError,
|
|
511
568
|
OAuth2UnknownClientError,
|
|
512
569
|
OAuth2RedirectUriMismatchError,
|
|
513
570
|
OAuth2AuthorizeRedirectError,
|
|
@@ -554,6 +611,11 @@ var routeMap = {
|
|
|
554
611
|
mfaStatus: { method: "GET", path: "/_auth/mfa/status" },
|
|
555
612
|
mfaStepUp: { method: "POST", path: "/_auth/mfa/step-up" },
|
|
556
613
|
mfaStepUpOptions: { method: "POST", path: "/_auth/mfa/step-up/options" },
|
|
614
|
+
setSessionBinding: { method: "POST", path: "/_auth/session/binding" },
|
|
615
|
+
getSessionBinding: { method: "GET", path: "/_auth/session/binding" },
|
|
616
|
+
sessionBindingDisableOptions: { method: "POST", path: "/_auth/session/binding/disable/options" },
|
|
617
|
+
sessionRenewOptions: { method: "POST", path: "/_auth/session/renew/options" },
|
|
618
|
+
sessionRenewVerify: { method: "POST", path: "/_auth/session/renew/verify" },
|
|
557
619
|
passkeyRegisterOptions: { method: "POST", path: "/_auth/passkeys/register/options" },
|
|
558
620
|
passkeyRegisterVerify: { method: "POST", path: "/_auth/passkeys/register/verify" },
|
|
559
621
|
passkeyLoginOptions: { method: "POST", path: "/_auth/passkeys/login/options" },
|
|
@@ -740,6 +802,7 @@ var BUILTIN_ROLE_PERMISSIONS = {
|
|
|
740
802
|
var KEY_ALGORITHM = ["ES256", "RS256"];
|
|
741
803
|
var KEY_PLATFORM = ["ios", "android", "web", "desktop"];
|
|
742
804
|
var KEY_DEVICE_NAME_MAX_LENGTH = 64;
|
|
805
|
+
var SESSION_BINDINGS = ["none", "passkey"];
|
|
743
806
|
var INVITATION_STATUSES = ["pending", "accepted", "expired", "cancelled"];
|
|
744
807
|
var USER_STATUSES = ["active", "inactive", "suspended", "pending_deletion", "deleted"];
|
|
745
808
|
var SOCIAL_PROVIDERS = ["google", "apple", "github", "kakao", "naver", "superself"];
|
|
@@ -3404,7 +3467,15 @@ var DeviceAuthPollResponseSchema = Type.Union([
|
|
|
3404
3467
|
publicId: Type.String(),
|
|
3405
3468
|
email: Type.Optional(Type.String()),
|
|
3406
3469
|
phone: Type.Optional(Type.String()),
|
|
3407
|
-
passwordChangeRequired: Type.Boolean()
|
|
3470
|
+
passwordChangeRequired: Type.Boolean(),
|
|
3471
|
+
// The approved branch is a `LoginResult` spread whole, so it carries the
|
|
3472
|
+
// binding fields a sign-in can carry (#97). In practice it never does: a
|
|
3473
|
+
// waiting device polls the backend directly, and a key is bound only on a
|
|
3474
|
+
// request that reached it through the trusted Next.js proxy. Declared
|
|
3475
|
+
// anyway, because the branch is whatever the login answered and the two
|
|
3476
|
+
// must not be able to drift apart.
|
|
3477
|
+
sessionBinding: Type.Optional(Type.Union(SESSION_BINDINGS.map((mode) => Type.Literal(mode)))),
|
|
3478
|
+
keyExpiresAtMillis: Type.Optional(Type.Integer())
|
|
3408
3479
|
})
|
|
3409
3480
|
], {
|
|
3410
3481
|
description: "Pending, or the login the approval produced"
|