@spfn/auth 0.3.0-beta.23 → 0.3.0-beta.25

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 (35) hide show
  1. package/README.md +328 -7
  2. package/dist/client-proof.d.ts +10 -1
  3. package/dist/client-proof.js +136 -11
  4. package/dist/client-proof.js.map +1 -1
  5. package/dist/client.d.ts +101 -1
  6. package/dist/client.js +65 -0
  7. package/dist/client.js.map +1 -1
  8. package/dist/config.d.ts +122 -0
  9. package/dist/config.js +53 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/crypto.d.ts +1 -1
  12. package/dist/errors.d.ts +159 -3
  13. package/dist/errors.js +95 -2
  14. package/dist/errors.js.map +1 -1
  15. package/dist/index.d.ts +52 -12
  16. package/dist/index.js +104 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/{machine-principals-CaEFq61K.d.ts → machine-principals-CdEgxOB1.d.ts} +2049 -771
  19. package/dist/nextjs/api.js +329 -37
  20. package/dist/nextjs/api.js.map +1 -1
  21. package/dist/nextjs/server.d.ts +59 -24
  22. package/dist/nextjs/server.js +105 -11
  23. package/dist/nextjs/server.js.map +1 -1
  24. package/dist/server.d.ts +415 -332
  25. package/dist/server.js +2933 -1545
  26. package/dist/server.js.map +1 -1
  27. package/dist/{session-Dfwu5g2W.d.ts → session-BbhAGZtA.d.ts} +57 -1
  28. package/dist/{types-DYyhze28.d.ts → types-CTdoTOxM.d.ts} +24 -1
  29. package/migrations/20260918184037_happy_mordo/migration.sql +4 -0
  30. package/migrations/20260918184037_happy_mordo/snapshot.json +6000 -0
  31. package/migrations/20260918184152_dear_rictor/migration.sql +3 -0
  32. package/migrations/20260918184152_dear_rictor/snapshot.json +6039 -0
  33. package/migrations/20260919023107_even_mikhail_rasputin/migration.sql +20 -0
  34. package/migrations/20260919023107_even_mikhail_rasputin/snapshot.json +6300 -0
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors/index.ts","../src/errors/auth-errors.ts"],"sourcesContent":["/**\n * Auth Error Exports\n */\n\nimport { ErrorRegistry } from '@spfn/core/errors';\n\nimport {\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n} from './auth-errors';\n\nexport {\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n} from './auth-errors';\n\nexport const authErrorRegistry = new ErrorRegistry();\nauthErrorRegistry.append([\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n]);\n\nexport * as AuthError from './auth-errors';\n","/**\n * Authentication & Authorization Error Classes\n *\n * Custom error classes for auth-specific scenarios\n */\n\nimport {\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n ConflictError,\n NotFoundError,\n HttpError,\n} from '@spfn/core/errors';\n\n/**\n * Invalid Credentials Error (401)\n *\n * Thrown when login credentials are incorrect\n */\nexport class InvalidCredentialsError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid credentials', details: data.details });\n this.name = 'InvalidCredentialsError';\n }\n}\n\n/**\n * Invalid Token Error (401)\n *\n * Thrown when authentication token is invalid or malformed\n */\nexport class InvalidTokenError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid authentication token', details: data.details });\n this.name = 'InvalidTokenError';\n }\n}\n\n/**\n * Invalid Social Token Error (401)\n *\n * Thrown when a social provider id_token fails verification\n * (bad signature, wrong issuer/audience, expired, or nonce mismatch).\n */\nexport class InvalidSocialTokenError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid social id_token', details: data.details });\n this.name = 'InvalidSocialTokenError';\n }\n}\n\n/**\n * Token Expired Error (401)\n *\n * Thrown when authentication token has expired\n */\nexport class TokenExpiredError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Authentication token has expired', details: data.details });\n this.name = 'TokenExpiredError';\n }\n}\n\n/**\n * Key Expired Error (401)\n *\n * Thrown when public key has expired\n */\nexport class KeyExpiredError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Public key has expired', details: data.details });\n this.name = 'KeyExpiredError';\n }\n}\n\n/**\n * Account Disabled Error (403)\n *\n * Thrown when user account is disabled or inactive\n */\nexport class AccountDisabledError extends ForbiddenError\n{\n constructor(data: { status?: string; message?: string; details?: Record<string, any> } = {})\n {\n const status = data.status || 'disabled';\n super({\n message: data.message || `Account is ${status}`,\n details: { status, ...data.details },\n });\n this.name = 'AccountDisabledError';\n }\n}\n\n/**\n * Account Pending Deletion Error (403)\n *\n * Thrown on login (password/OAuth/authenticate) when the account is within its\n * deletion grace period. Carries `purgeScheduledAt` so the client can offer a\n * recovery flow instead of a generic \"disabled\" message.\n */\nexport class AccountPendingDeletionError extends ForbiddenError\n{\n constructor(data: { purgeScheduledAt?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Account is scheduled for deletion',\n details: { status: 'pending_deletion', purgeScheduledAt: data.purgeScheduledAt, ...data.details },\n });\n this.name = 'AccountPendingDeletionError';\n }\n}\n\n/**\n * Deletion Already Requested Error (409)\n *\n * Thrown when requesting deletion for an account that already has a pending\n * deletion request (or has already been purged).\n */\nexport class DeletionAlreadyRequestedError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Account deletion has already been requested', details: data.details });\n this.name = 'DeletionAlreadyRequestedError';\n }\n}\n\n/**\n * Deletion Not Requested Error (404)\n *\n * Thrown when trying to cancel/purge a deletion for an account that has no\n * pending deletion request.\n */\nexport class DeletionNotRequestedError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'No pending account deletion request found', details: data.details });\n this.name = 'DeletionNotRequestedError';\n }\n}\n\n/**\n * Immediate Deletion Not Allowed Error (403)\n *\n * Thrown when a self-service caller requests `immediate: true` but the server\n * has not enabled `deletion.allowSelfImmediate`.\n */\nexport class ImmediateDeletionNotAllowedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Immediate self-service deletion is not enabled', details: data.details });\n this.name = 'ImmediateDeletionNotAllowedError';\n }\n}\n\n/**\n * Account Already Exists Error (409)\n *\n * Thrown when trying to register with existing email/phone\n */\nexport class AccountAlreadyExistsError extends ConflictError\n{\n constructor(data: { identifier?: string; identifierType?: 'email' | 'phone'; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Account already exists',\n details: {\n identifier: data.identifier,\n identifierType: data.identifierType,\n ...data.details,\n },\n });\n this.name = 'AccountAlreadyExistsError';\n }\n}\n\n/**\n * Registration Rejected Error (403)\n *\n * Thrown by the app-injected beforeRegister hook to reject a registration\n * (age gate, domain restriction, block list, ...)\n */\nexport class RegistrationRejectedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Registration rejected', details: data.details });\n this.name = 'RegistrationRejectedError';\n }\n}\n\n/**\n * Invalid Verification Code Error (400)\n *\n * Thrown when verification code is invalid, expired, or already used\n */\nexport class InvalidVerificationCodeError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid verification code', details: data.details });\n this.name = 'InvalidVerificationCodeError';\n }\n}\n\n/**\n * Invalid Verification Token Error (400)\n *\n * Thrown when verification token is invalid or expired\n */\nexport class InvalidVerificationTokenError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid or expired verification token', details: data.details });\n this.name = 'InvalidVerificationTokenError';\n }\n}\n\n/**\n * Key ID Already Registered Error (409)\n *\n * Thrown when a sign-in submits a keyId that is already taken — the client's own\n * revoked keyId, or a keyId belonging to another user. `keyId` is unique across\n * all users, so either case would collide on insert.\n *\n * The same error covers both cases on purpose: a distinguishable response would\n * let a caller probe whether an arbitrary keyId exists. Revoked stays revoked —\n * the client must generate a fresh keyId and retry.\n */\nexport class KeyIdAlreadyRegisteredError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This keyId is already registered. Generate a new keyId and retry.',\n details: data.details,\n });\n this.name = 'KeyIdAlreadyRegisteredError';\n }\n}\n\n/**\n * Invalid Key Fingerprint Error (400)\n *\n * Thrown when public key fingerprint doesn't match the public key\n */\nexport class InvalidKeyFingerprintError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid key fingerprint', details: data.details });\n this.name = 'InvalidKeyFingerprintError';\n }\n}\n\n/**\n * Key Algorithm Mismatch Error (400)\n *\n * Thrown when the submitted public key's SPKI type is not the one its declared\n * algorithm needs — a P-256 EC key declared RS256, an RSA key declared ES256, a\n * curve other than P-256 declared ES256, or bytes that are no SPKI key at all.\n *\n * The algorithm is stored beside the key and read back at proof verification;\n * nothing re-derives it from the key material. So a mismatch accepted here\n * surfaces only after the device believes it is enrolled, on every request it\n * then makes. It is refused at registration instead, wherever key material is\n * stored: register, login, rotate, invitation acceptance and device start.\n */\nexport class KeyAlgorithmMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Public key type does not match the declared algorithm',\n details: data.details,\n });\n this.name = 'KeyAlgorithmMismatchError';\n }\n}\n\n/**\n * Key Not Found Error (404)\n *\n * Thrown when a key operation names a keyId the caller does not own. It says\n * nothing about whether that keyId exists on another account — the repository\n * scopes every lookup by userId, so the answer is only ever \"not yours\".\n */\nexport class KeyNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Key not found', details: data.details });\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * Revoke-All Link Error (404)\n *\n * Thrown when a signed sign-out-everywhere link cannot be acted on: unknown,\n * expired, already spent, superseded by a newer one, issued against a key\n * generation that has since moved, or belonging to an account that is not\n * active.\n *\n * One error for every one of those, and the same body for each. Telling an\n * expired link from an unknown one would tell whoever is holding a random value\n * that it named a real outstanding link, and the sibling link flows refuse the\n * same way for the same reason. The specific cause is logged.\n *\n * 404 rather than the 401 the password-reset link answers with: there is no\n * credential here to have been wrong. The address the mail went to is the proof,\n * and what the caller presented either names an outstanding link or names\n * nothing.\n */\nexport class RevokeAllLinkError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This sign-out link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'RevokeAllLinkError';\n }\n}\n\n/**\n * Device Auth Not Found Error (404)\n *\n * Thrown when a device-code operation names a code the server cannot act on: one\n * that was never issued, and one whose record has already been consumed.\n *\n * Those two are answered identically on purpose. A consumed record is a login\n * that finished, and saying so would tell whoever holds the code that it was\n * real — which is the difference between guessing at random and knowing a guess\n * landed. Every route that accepts a code is rate limited for the same reason.\n */\nexport class DeviceAuthNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Device authorization not found', details: data.details });\n this.name = 'DeviceAuthNotFoundError';\n }\n}\n\n/**\n * Device Auth Expired Error (400)\n *\n * Thrown when a device-code operation names a record whose TTL has run out,\n * whatever state it is in. The waiting device starts again; the approver is told\n * the code on the other screen is stale.\n *\n * 400 rather than 401: on the approve and deny routes the caller's own session is\n * fine, and answering 401 would send a signed-in user to a login screen over a\n * code that simply sat too long.\n */\nexport class DeviceAuthExpiredError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device code has expired. Start again on the other device.',\n details: data.details,\n });\n this.name = 'DeviceAuthExpiredError';\n }\n}\n\n/**\n * Device Auth Already Handled Error (409)\n *\n * Thrown when an approve, deny or info call names a record that has already been\n * approved or denied. A decision on a device is made once — a second approval\n * would let one code be answered twice, and re-approving a record the owner\n * denied would undo the refusal.\n *\n * This is also what the loser of two concurrent approvals sees, since the\n * transition names the state it moves from and only one call can match it.\n */\nexport class DeviceAuthAlreadyHandledError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device request has already been answered',\n details: data.details,\n });\n this.name = 'DeviceAuthAlreadyHandledError';\n }\n}\n\n/**\n * Device Auth Denied Error (403)\n *\n * Thrown when the waiting device polls a record its owner refused. Distinct from\n * a pending answer, and distinct from a code that does not exist: the device\n * asked a person and the person said no, so it should stop polling and say so\n * rather than time out looking like a network fault.\n */\nexport class DeviceAuthDeniedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device request was denied',\n details: data.details,\n });\n this.name = 'DeviceAuthDeniedError';\n }\n}\n\n/**\n * Nonce Key Binding Error (400)\n *\n * Thrown when a native id_token sign-in submits a nonce that is not the public\n * key's fingerprint. The nonce is what the provider echoed back inside the\n * id_token, so tying it to the key is what proves the id_token and the key came\n * from the same device — see the native section of the README.\n */\nexport class NonceKeyBindingError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'nonce must be the fingerprint of the submitted public key',\n details: data.details,\n });\n this.name = 'NonceKeyBindingError';\n }\n}\n\n/**\n * Native Sign-In Unsupported Error (400)\n *\n * Thrown when a provider is asked for native id_token sign-in and has no\n * implementation for it — a server configuration fact, not something the user\n * did. A client reading this hides that provider's native button instead of\n * asking the user to try again.\n *\n * Split out of ValidationError because the other native-enrollment refusal\n * (linking to an account whose email the provider never verified) needs a\n * different response from the app, and one code cannot ask for two.\n */\nexport class NativeSignInUnsupportedError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This provider does not support native id_token sign-in.',\n details: data.details,\n });\n this.name = 'NativeSignInUnsupportedError';\n }\n}\n\n/**\n * Invalid Signup Link Error (400)\n *\n * Thrown when an emailed signup confirmation link is unknown, expired, already\n * consumed, or superseded by a newer request for the same address.\n *\n * One error for all four states, on purpose. Distinguishing \"expired\" from\n * \"unknown\" tells a caller holding a random token whether it named a real\n * pending signup, which is exactly the enumeration the request step avoids. The\n * specific reason is logged.\n */\nexport class InvalidSignupLinkError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This signup link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'InvalidSignupLinkError';\n }\n}\n\n/**\n * Invalid Signup Setup Session Error (401)\n *\n * Thrown when the password-setup session backing a verified-email signup is\n * missing, unknown, expired, superseded or already used.\n *\n * One error for every one of those, on purpose: telling a caller which of them\n * applies tells them whether an address is mid-signup, which is the same\n * enumeration the request step is careful not to leak.\n */\nexport class InvalidSignupSetupSessionError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Password setup session is invalid or has expired. Start the signup again.',\n details: data.details,\n });\n this.name = 'InvalidSignupSetupSessionError';\n }\n}\n\n/**\n * Password Reset Link Error (401)\n *\n * Thrown when an emailed password reset link is unknown, expired, already\n * consumed, superseded by a newer request, or belongs to an account that is no\n * longer active.\n *\n * One error for every one of those, on purpose. Distinguishing \"expired\" from\n * \"unknown\" tells a caller holding a random token whether it named a real\n * pending reset, which is exactly the enumeration the request step avoids. The\n * specific reason is logged.\n */\nexport class PasswordResetLinkError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This password reset link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'PasswordResetLinkError';\n }\n}\n\n/**\n * Password Reset Session Error (401)\n *\n * Thrown when the password-setup session backing a reset is missing, unknown,\n * expired, superseded or already used.\n *\n * One error for every one of those, for the same reason the link error is one\n * error: which of them applies tells a caller whether an account is mid-reset,\n * and that is the enumeration the request step is careful not to leak.\n */\nexport class PasswordResetSessionError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Password reset session is invalid or has expired. Request a new link.',\n details: data.details,\n });\n this.name = 'PasswordResetSessionError';\n }\n}\n\n/**\n * Unverified Email Link Error (400)\n *\n * Thrown when a social identity carries an email that already belongs to an\n * account, but the provider never verified it. Linking on an unverified email\n * is account takeover, so the refusal stands and the user is sent to a path\n * that proves the address.\n *\n * This says an account exists for that address. It is not a leak introduced\n * here: the message this replaces already stated the same fact in prose, and\n * the paths that must not disclose account existence (password login, deletion\n * re-auth, verification issuance) answer uniformly and are untouched.\n */\nexport class UnverifiedEmailLinkError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'Cannot link to existing account with unverified email. Please verify your email with the provider first.',\n details: data.details,\n });\n this.name = 'UnverifiedEmailLinkError';\n }\n}\n\n/**\n * Verification Token Purpose Mismatch Error (400)\n *\n * Thrown when verification token purpose doesn't match expected purpose\n */\nexport class VerificationTokenPurposeMismatchError extends ValidationError\n{\n constructor(data: { expected?: string; actual?: string; message?: string; details?: Record<string, any> } = {})\n {\n const expected = data.expected || 'unknown';\n const actual = data.actual || 'unknown';\n super({\n message: data.message || `Verification token is for ${actual}, but ${expected} was expected`,\n details: { expected, actual, ...data.details },\n });\n this.name = 'VerificationTokenPurposeMismatchError';\n }\n}\n\n/**\n * Verification Token Target Mismatch Error (400)\n *\n * Thrown when verification token target doesn't match provided email/phone\n */\nexport class VerificationTokenTargetMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Verification token does not match provided email/phone',\n details: data.details,\n });\n this.name = 'VerificationTokenTargetMismatchError';\n }\n}\n\n/**\n * Reserved Username Error (400)\n *\n * Thrown when trying to use a reserved/prohibited username\n */\nexport class ReservedUsernameError extends ValidationError\n{\n constructor(data: { username?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This username is reserved',\n details: { username: data.username, ...data.details },\n });\n this.name = 'ReservedUsernameError';\n }\n}\n\n/**\n * Username Already Taken Error (409)\n *\n * Thrown when trying to set a username that is already in use\n */\nexport class UsernameAlreadyTakenError extends ConflictError\n{\n constructor(data: { username?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Username is already taken',\n details: { username: data.username, ...data.details },\n });\n this.name = 'UsernameAlreadyTakenError';\n }\n}\n\n/**\n * Insufficient Permissions Error (403)\n *\n * Thrown when user lacks required permissions for the operation\n */\nexport class InsufficientPermissionsError extends ForbiddenError\n{\n constructor(data: { requiredPermissions?: string[]; message?: string; details?: Record<string, any> } = {})\n {\n const requiredPermissions = data.requiredPermissions || [];\n super({\n message: data.message || `Missing required permissions: ${requiredPermissions.join(', ')}`,\n details: { requiredPermissions, ...data.details },\n });\n this.name = 'InsufficientPermissionsError';\n }\n}\n\n/**\n * Insufficient Role Error (403)\n *\n * Thrown when user lacks required role for the operation\n */\nexport class InsufficientRoleError extends ForbiddenError\n{\n constructor(data: { requiredRoles?: string[]; message?: string; details?: Record<string, any> } = {})\n {\n const requiredRoles = data.requiredRoles || [];\n super({\n message: data.message || `Required roles: ${requiredRoles.join(', ')}`,\n details: { requiredRoles, ...data.details },\n });\n this.name = 'InsufficientRoleError';\n }\n}\n\n/**\n * Passkey Challenge Error (401)\n *\n * Thrown when the challenge a WebAuthn ceremony presents is unknown, expired,\n * already spent, minted for the other ceremony, or minted for another account.\n *\n * One error for all five, on purpose. Telling a caller which applies tells them\n * whether a challenge they did not mint exists and what it was for, and the\n * remedy is the same in every case: start the ceremony again.\n */\nexport class PasskeyChallengeError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This passkey challenge is no longer valid. Try again.',\n details: data.details,\n });\n this.name = 'PasskeyChallengeError';\n }\n}\n\n/**\n * Passkey Verification Error (401)\n *\n * Thrown when an assertion or attestation does not verify: wrong origin, wrong\n * rpId, a bad signature, a regressed signature counter — or, on login, a\n * credential that is unknown or has been revoked.\n *\n * Those last two share this error with the cryptographic failures deliberately.\n * A distinct \"no such passkey\" would answer, to anyone holding a credential id,\n * whether it is enrolled here — and a revoked credential answering differently\n * from an unknown one would say the account once had it.\n */\nexport class PasskeyVerificationError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Passkey verification failed.',\n details: data.details,\n });\n this.name = 'PasskeyVerificationError';\n }\n}\n\n/**\n * Passkey Not Found Error (404)\n *\n * Thrown when a management operation names a passkey the caller does not own,\n * or one already revoked. Every lookup is owner-scoped, so the answer is only\n * ever \"not yours\" and says nothing about other accounts.\n */\nexport class PasskeyNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Passkey not found',\n details: data.details,\n });\n this.name = 'PasskeyNotFoundError';\n }\n}\n\n/**\n * Passkey Already Registered Error (409)\n *\n * Thrown when the credential presented for enrollment is already on file for\n * some account — including one that revoked it. A credential id is reserved for\n * good once used, so this is also the answer to re-enrolling one's own revoked\n * passkey.\n */\nexport class PasskeyAlreadyRegisteredError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This passkey is already registered',\n details: data.details,\n });\n this.name = 'PasskeyAlreadyRegisteredError';\n }\n}\n\n/**\n * Recent Authentication Required Error (403)\n *\n * Thrown when enrolling or revoking a passkey from a session that proved itself\n * too long ago and carried no password. Clients branch on `code` to know to\n * prompt for the password rather than to show a generic refusal, so the code is\n * a stable field rather than a message they would have to match on.\n */\nexport class RecentAuthenticationRequiredError extends ForbiddenError\n{\n readonly code = 'RECENT_AUTH_REQUIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Confirm it is you before changing passkeys. Sign in again or send your current password.',\n details: data.details,\n });\n this.name = 'RecentAuthenticationRequiredError';\n }\n}\n\n/**\n * Last Recovery Credential Error (409)\n *\n * Thrown when revoking a passkey would leave the account with no way back in:\n * no other live passkey, no password, and no linked social account. There is no\n * password reset in this package, so that state is not recoverable by support\n * either — the refusal is the only thing standing between the owner and a\n * locked account.\n *\n * Clients branch on `code` to offer \"set a password first\" instead of a generic\n * refusal.\n */\nexport class LastRecoveryCredentialError extends ConflictError\n{\n readonly code = 'LAST_RECOVERY_CREDENTIAL';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'This is the only way you can sign in. Set a password or link a social account before removing it.',\n details: data.details,\n });\n this.name = 'LastRecoveryCredentialError';\n }\n}\n\n/**\n * Passkey Config Error (500)\n *\n * Thrown at boot when the passkey relying-party configuration cannot be honoured\n * — an origin that is not https outside localhost, an origin off the rpId, an\n * unsupported user-verification value.\n *\n * A refusal at boot rather than at the first ceremony: every one of these makes\n * every passkey operation fail, and the drift is between environments, so the\n * deploy that introduces it is where it has to surface.\n */\nexport class PasskeyConfigError extends HttpError\n{\n constructor(data: { message: string; details?: Record<string, any> })\n {\n super({\n message: data.message,\n statusCode: 500,\n details: data.details,\n });\n this.name = 'PasskeyConfigError';\n }\n}\n\n/**\n * OAuth2 Unknown Client Error (400)\n *\n * Thrown by the API authorize endpoints when `client_id` names no registered\n * client. One of the two refusals that must NOT be turned into a redirect: with\n * no client there is no registered redirect URI, so the only place left to send\n * the error is the one the request supplied — which is exactly the open redirect\n * this rule exists to close. The consent screen shows it instead.\n */\nexport class OAuth2UnknownClientError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Unknown OAuth client',\n details: { error: 'unknown_client', ...data.details },\n });\n this.name = 'OAuth2UnknownClientError';\n }\n}\n\n/**\n * OAuth2 Redirect URI Mismatch Error (400)\n *\n * Thrown when `redirect_uri` is not one the client registered. The second\n * non-redirectable refusal, for the same reason as the first: redirecting the\n * error to an unregistered URI is the attack.\n */\nexport class OAuth2RedirectUriMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'redirect_uri does not match a registered URI for this client',\n details: { error: 'redirect_uri_mismatch', ...data.details },\n });\n this.name = 'OAuth2RedirectUriMismatchError';\n }\n}\n\n/**\n * OAuth2 Authorize Redirect Error (400)\n *\n * Every other authorize-time refusal — `invalid_request`, `invalid_scope`,\n * `invalid_target`, `access_denied`. The client and its redirect URI are both\n * known by the time these are decided, so RFC 6749 §4.1.2.1 says the error goes\n * back to the client as query parameters on that URI rather than to the person.\n *\n * The API cannot perform that redirect — it is answering the web app's consent\n * handler, not the browser — so it carries the pieces in `details` and the\n * handler builds the 302. `redirectUri` is the registered-and-matched value, not\n * the raw parameter, which is what makes it safe to send somebody to.\n */\nexport class OAuth2AuthorizeRedirectError extends ValidationError\n{\n constructor(data: {\n error: string;\n redirectUri: string;\n state?: string;\n message?: string;\n details?: Record<string, any>;\n })\n {\n super({\n message: data.message || `OAuth authorize request refused: ${data.error}`,\n details: {\n error: data.error,\n redirectUri: data.redirectUri,\n state: data.state,\n ...data.details,\n },\n });\n this.name = 'OAuth2AuthorizeRedirectError';\n }\n}\n\n/**\n * OAuth2 Grant Not Found Error (404)\n *\n * Thrown by `DELETE /_auth/oauth2/grants/:id` when the caller owns no live grant\n * of that id. A grant belonging to somebody else answers the same way as one\n * that never existed — the id is a number in a URL, and telling the two apart\n * would let anyone count other people's connected clients.\n */\nexport class OAuth2GrantNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'No such connected application', details: data.details });\n this.name = 'OAuth2GrantNotFoundError';\n }\n}\n\n/**\n * MFA Already Enrolled Error (409)\n *\n * Thrown when `totp/enroll` is called on an account whose TOTP is already\n * confirmed. Replacing a working second factor is `disable` followed by a fresh\n * enrolment, both step-up gated — an enrol that quietly overwrote a confirmed\n * secret would be a way to swap someone's authenticator for your own.\n */\nexport class MfaAlreadyEnrolledError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'A second factor is already enrolled on this account',\n details: data.details,\n });\n this.name = 'MfaAlreadyEnrolledError';\n }\n}\n\n/**\n * MFA Not Enrolled Error (400)\n *\n * Thrown when a call needs an enrolment that is not there: `totp/confirm` with\n * no pending secret — including the row its own five failed attempts deleted —\n * or `recovery/regenerate` on an account with no second factor. `disable` is\n * deliberately not one of them; it answers 204 either way, because \"make sure\n * MFA is off\" has already succeeded.\n */\nexport class MfaNotEnrolledError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'No second-factor enrolment is in progress on this account',\n details: data.details,\n });\n this.name = 'MfaNotEnrolledError';\n }\n}\n\n/**\n * MFA Verification Failed Error (401)\n *\n * Thrown when a submitted code does not verify: a wrong or stale TOTP, a code\n * from a step already spent, a recovery code that is used, from an older\n * generation or another account's, or an assertion from a passkey the owner\n * never marked as a second factor.\n *\n * One body for all of them. Which one applies describes state the caller is\n * guessing at, and the remedy — look at the authenticator again — is the same.\n */\nexport class MfaVerificationFailedError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'That code did not verify',\n details: data.details,\n });\n this.name = 'MfaVerificationFailedError';\n }\n}\n\n/**\n * Step Up Required Error (403)\n *\n * Thrown when an enrolled account asks for a sensitive change from a device\n * whose second factor was last verified longer ago than the step-up window. A\n * stolen session alone therefore cannot change a password, sign every device\n * out, or take the second factor off.\n *\n * 403 and not 401, on the same reasoning as `RecentAuthenticationRequiredError`,\n * which it sits beside: a 401 on an authenticated route is what a web client\n * reads as \"the session is gone\", so it would sign the user out instead of\n * asking for a code. Clients branch on `code` to send the user to\n * `POST /_auth/mfa/step-up` and retry.\n */\nexport class StepUpRequiredError extends ForbiddenError\n{\n readonly code = 'STEP_UP_REQUIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Confirm your second factor before making this change.',\n details: data.details,\n });\n this.name = 'StepUpRequiredError';\n }\n}\n\n/**\n * MFA Config Error (500)\n *\n * Thrown when the at-rest keyring cannot serve a second factor:\n * `SPFN_AUTH_TOKEN_ENCRYPTION_KEYS` is unset, or a stored secret names a key id\n * that has been dropped from it.\n *\n * Deliberately not the 401 a wrong code gets. The two have nothing in common: a\n * wrong code is one person looking at the wrong line of their authenticator,\n * and a broken keyring is every enrolled user locked out at once by a deploy.\n * An operator has to be able to tell them apart from the response alone.\n */\nexport class MfaConfigError extends HttpError\n{\n constructor(data: { message: string; details?: Record<string, any> })\n {\n super({\n message: data.message,\n statusCode: 500,\n details: data.details,\n });\n this.name = 'MfaConfigError';\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors/index.ts","../src/errors/auth-errors.ts"],"sourcesContent":["/**\n * Auth Error Exports\n */\n\nimport { ErrorRegistry } from '@spfn/core/errors';\n\nimport {\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n SessionBindingUnavailableError,\n SessionRenewalRequiredError,\n SessionRenewalRefusedError,\n SessionContextChangedError,\n SessionResealFailedError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n SessionPendingMismatchError,\n SessionPendingExpiredError,\n} from './auth-errors';\n\nexport {\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n SessionBindingUnavailableError,\n SessionRenewalRequiredError,\n SessionRenewalRefusedError,\n SessionContextChangedError,\n SessionResealFailedError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n SessionPendingMismatchError,\n SessionPendingExpiredError,\n} from './auth-errors';\n\nexport const authErrorRegistry = new ErrorRegistry();\nauthErrorRegistry.append([\n InvalidCredentialsError,\n InvalidTokenError,\n InvalidSocialTokenError,\n TokenExpiredError,\n KeyExpiredError,\n AccountDisabledError,\n AccountPendingDeletionError,\n DeletionAlreadyRequestedError,\n DeletionNotRequestedError,\n ImmediateDeletionNotAllowedError,\n AccountAlreadyExistsError,\n RegistrationRejectedError,\n ReservedUsernameError,\n UsernameAlreadyTakenError,\n InvalidVerificationCodeError,\n InvalidVerificationTokenError,\n InvalidKeyFingerprintError,\n KeyAlgorithmMismatchError,\n NonceKeyBindingError,\n NativeSignInUnsupportedError,\n UnverifiedEmailLinkError,\n InvalidSignupLinkError,\n InvalidSignupSetupSessionError,\n PasswordResetLinkError,\n PasswordResetSessionError,\n KeyNotFoundError,\n KeyIdAlreadyRegisteredError,\n RevokeAllLinkError,\n DeviceAuthNotFoundError,\n DeviceAuthExpiredError,\n DeviceAuthAlreadyHandledError,\n DeviceAuthDeniedError,\n VerificationTokenPurposeMismatchError,\n VerificationTokenTargetMismatchError,\n InsufficientPermissionsError,\n InsufficientRoleError,\n PasskeyChallengeError,\n PasskeyVerificationError,\n PasskeyNotFoundError,\n PasskeyAlreadyRegisteredError,\n RecentAuthenticationRequiredError,\n LastRecoveryCredentialError,\n PasskeyConfigError,\n SessionBindingUnavailableError,\n SessionRenewalRequiredError,\n SessionRenewalRefusedError,\n SessionContextChangedError,\n SessionResealFailedError,\n OAuth2UnknownClientError,\n OAuth2RedirectUriMismatchError,\n OAuth2AuthorizeRedirectError,\n OAuth2GrantNotFoundError,\n MfaAlreadyEnrolledError,\n MfaNotEnrolledError,\n MfaVerificationFailedError,\n StepUpRequiredError,\n MfaConfigError,\n SessionPendingMismatchError,\n SessionPendingExpiredError,\n]);\n\nexport * as AuthError from './auth-errors';\n","/**\n * Authentication & Authorization Error Classes\n *\n * Custom error classes for auth-specific scenarios\n */\n\nimport {\n BadRequestError,\n ValidationError,\n UnauthorizedError,\n ForbiddenError,\n ConflictError,\n NotFoundError,\n HttpError,\n InternalServerError,\n} from '@spfn/core/errors';\n\n/**\n * Invalid Credentials Error (401)\n *\n * Thrown when login credentials are incorrect\n */\nexport class InvalidCredentialsError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid credentials', details: data.details });\n this.name = 'InvalidCredentialsError';\n }\n}\n\n/**\n * Invalid Token Error (401)\n *\n * Thrown when authentication token is invalid or malformed\n */\nexport class InvalidTokenError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid authentication token', details: data.details });\n this.name = 'InvalidTokenError';\n }\n}\n\n/**\n * Invalid Social Token Error (401)\n *\n * Thrown when a social provider id_token fails verification\n * (bad signature, wrong issuer/audience, expired, or nonce mismatch).\n */\nexport class InvalidSocialTokenError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid social id_token', details: data.details });\n this.name = 'InvalidSocialTokenError';\n }\n}\n\n/**\n * Token Expired Error (401)\n *\n * Thrown when authentication token has expired\n */\nexport class TokenExpiredError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Authentication token has expired', details: data.details });\n this.name = 'TokenExpiredError';\n }\n}\n\n/**\n * Key Expired Error (401)\n *\n * Thrown when public key has expired\n */\nexport class KeyExpiredError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Public key has expired', details: data.details });\n this.name = 'KeyExpiredError';\n }\n}\n\n/**\n * Account Disabled Error (403)\n *\n * Thrown when user account is disabled or inactive\n */\nexport class AccountDisabledError extends ForbiddenError\n{\n constructor(data: { status?: string; message?: string; details?: Record<string, any> } = {})\n {\n const status = data.status || 'disabled';\n super({\n message: data.message || `Account is ${status}`,\n details: { status, ...data.details },\n });\n this.name = 'AccountDisabledError';\n }\n}\n\n/**\n * Account Pending Deletion Error (403)\n *\n * Thrown on login (password/OAuth/authenticate) when the account is within its\n * deletion grace period. Carries `purgeScheduledAt` so the client can offer a\n * recovery flow instead of a generic \"disabled\" message.\n */\nexport class AccountPendingDeletionError extends ForbiddenError\n{\n constructor(data: { purgeScheduledAt?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Account is scheduled for deletion',\n details: { status: 'pending_deletion', purgeScheduledAt: data.purgeScheduledAt, ...data.details },\n });\n this.name = 'AccountPendingDeletionError';\n }\n}\n\n/**\n * Deletion Already Requested Error (409)\n *\n * Thrown when requesting deletion for an account that already has a pending\n * deletion request (or has already been purged).\n */\nexport class DeletionAlreadyRequestedError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Account deletion has already been requested', details: data.details });\n this.name = 'DeletionAlreadyRequestedError';\n }\n}\n\n/**\n * Deletion Not Requested Error (404)\n *\n * Thrown when trying to cancel/purge a deletion for an account that has no\n * pending deletion request.\n */\nexport class DeletionNotRequestedError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'No pending account deletion request found', details: data.details });\n this.name = 'DeletionNotRequestedError';\n }\n}\n\n/**\n * Immediate Deletion Not Allowed Error (403)\n *\n * Thrown when a self-service caller requests `immediate: true` but the server\n * has not enabled `deletion.allowSelfImmediate`.\n */\nexport class ImmediateDeletionNotAllowedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Immediate self-service deletion is not enabled', details: data.details });\n this.name = 'ImmediateDeletionNotAllowedError';\n }\n}\n\n/**\n * Account Already Exists Error (409)\n *\n * Thrown when trying to register with existing email/phone\n */\nexport class AccountAlreadyExistsError extends ConflictError\n{\n constructor(data: { identifier?: string; identifierType?: 'email' | 'phone'; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Account already exists',\n details: {\n identifier: data.identifier,\n identifierType: data.identifierType,\n ...data.details,\n },\n });\n this.name = 'AccountAlreadyExistsError';\n }\n}\n\n/**\n * Registration Rejected Error (403)\n *\n * Thrown by the app-injected beforeRegister hook to reject a registration\n * (age gate, domain restriction, block list, ...)\n */\nexport class RegistrationRejectedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Registration rejected', details: data.details });\n this.name = 'RegistrationRejectedError';\n }\n}\n\n/**\n * Invalid Verification Code Error (400)\n *\n * Thrown when verification code is invalid, expired, or already used\n */\nexport class InvalidVerificationCodeError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid verification code', details: data.details });\n this.name = 'InvalidVerificationCodeError';\n }\n}\n\n/**\n * Invalid Verification Token Error (400)\n *\n * Thrown when verification token is invalid or expired\n */\nexport class InvalidVerificationTokenError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid or expired verification token', details: data.details });\n this.name = 'InvalidVerificationTokenError';\n }\n}\n\n/**\n * Key ID Already Registered Error (409)\n *\n * Thrown when a sign-in submits a keyId that is already taken — the client's own\n * revoked keyId, or a keyId belonging to another user. `keyId` is unique across\n * all users, so either case would collide on insert.\n *\n * The same error covers both cases on purpose: a distinguishable response would\n * let a caller probe whether an arbitrary keyId exists. Revoked stays revoked —\n * the client must generate a fresh keyId and retry.\n */\nexport class KeyIdAlreadyRegisteredError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This keyId is already registered. Generate a new keyId and retry.',\n details: data.details,\n });\n this.name = 'KeyIdAlreadyRegisteredError';\n }\n}\n\n/**\n * Invalid Key Fingerprint Error (400)\n *\n * Thrown when public key fingerprint doesn't match the public key\n */\nexport class InvalidKeyFingerprintError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Invalid key fingerprint', details: data.details });\n this.name = 'InvalidKeyFingerprintError';\n }\n}\n\n/**\n * Key Algorithm Mismatch Error (400)\n *\n * Thrown when the submitted public key's SPKI type is not the one its declared\n * algorithm needs — a P-256 EC key declared RS256, an RSA key declared ES256, a\n * curve other than P-256 declared ES256, or bytes that are no SPKI key at all.\n *\n * The algorithm is stored beside the key and read back at proof verification;\n * nothing re-derives it from the key material. So a mismatch accepted here\n * surfaces only after the device believes it is enrolled, on every request it\n * then makes. It is refused at registration instead, wherever key material is\n * stored: register, login, rotate, invitation acceptance and device start.\n */\nexport class KeyAlgorithmMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Public key type does not match the declared algorithm',\n details: data.details,\n });\n this.name = 'KeyAlgorithmMismatchError';\n }\n}\n\n/**\n * Key Not Found Error (404)\n *\n * Thrown when a key operation names a keyId the caller does not own. It says\n * nothing about whether that keyId exists on another account — the repository\n * scopes every lookup by userId, so the answer is only ever \"not yours\".\n */\nexport class KeyNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Key not found', details: data.details });\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * Revoke-All Link Error (404)\n *\n * Thrown when a signed sign-out-everywhere link cannot be acted on: unknown,\n * expired, already spent, superseded by a newer one, issued against a key\n * generation that has since moved, or belonging to an account that is not\n * active.\n *\n * One error for every one of those, and the same body for each. Telling an\n * expired link from an unknown one would tell whoever is holding a random value\n * that it named a real outstanding link, and the sibling link flows refuse the\n * same way for the same reason. The specific cause is logged.\n *\n * 404 rather than the 401 the password-reset link answers with: there is no\n * credential here to have been wrong. The address the mail went to is the proof,\n * and what the caller presented either names an outstanding link or names\n * nothing.\n */\nexport class RevokeAllLinkError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This sign-out link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'RevokeAllLinkError';\n }\n}\n\n/**\n * Device Auth Not Found Error (404)\n *\n * Thrown when a device-code operation names a code the server cannot act on: one\n * that was never issued, and one whose record has already been consumed.\n *\n * Those two are answered identically on purpose. A consumed record is a login\n * that finished, and saying so would tell whoever holds the code that it was\n * real — which is the difference between guessing at random and knowing a guess\n * landed. Every route that accepts a code is rate limited for the same reason.\n */\nexport class DeviceAuthNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'Device authorization not found', details: data.details });\n this.name = 'DeviceAuthNotFoundError';\n }\n}\n\n/**\n * Device Auth Expired Error (400)\n *\n * Thrown when a device-code operation names a record whose TTL has run out,\n * whatever state it is in. The waiting device starts again; the approver is told\n * the code on the other screen is stale.\n *\n * 400 rather than 401: on the approve and deny routes the caller's own session is\n * fine, and answering 401 would send a signed-in user to a login screen over a\n * code that simply sat too long.\n */\nexport class DeviceAuthExpiredError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device code has expired. Start again on the other device.',\n details: data.details,\n });\n this.name = 'DeviceAuthExpiredError';\n }\n}\n\n/**\n * Device Auth Already Handled Error (409)\n *\n * Thrown when an approve, deny or info call names a record that has already been\n * approved or denied. A decision on a device is made once — a second approval\n * would let one code be answered twice, and re-approving a record the owner\n * denied would undo the refusal.\n *\n * This is also what the loser of two concurrent approvals sees, since the\n * transition names the state it moves from and only one call can match it.\n */\nexport class DeviceAuthAlreadyHandledError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device request has already been answered',\n details: data.details,\n });\n this.name = 'DeviceAuthAlreadyHandledError';\n }\n}\n\n/**\n * Device Auth Denied Error (403)\n *\n * Thrown when the waiting device polls a record its owner refused. Distinct from\n * a pending answer, and distinct from a code that does not exist: the device\n * asked a person and the person said no, so it should stop polling and say so\n * rather than time out looking like a network fault.\n */\nexport class DeviceAuthDeniedError extends ForbiddenError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This device request was denied',\n details: data.details,\n });\n this.name = 'DeviceAuthDeniedError';\n }\n}\n\n/**\n * Nonce Key Binding Error (400)\n *\n * Thrown when a native id_token sign-in submits a nonce that is not the public\n * key's fingerprint. The nonce is what the provider echoed back inside the\n * id_token, so tying it to the key is what proves the id_token and the key came\n * from the same device — see the native section of the README.\n */\nexport class NonceKeyBindingError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'nonce must be the fingerprint of the submitted public key',\n details: data.details,\n });\n this.name = 'NonceKeyBindingError';\n }\n}\n\n/**\n * Native Sign-In Unsupported Error (400)\n *\n * Thrown when a provider is asked for native id_token sign-in and has no\n * implementation for it — a server configuration fact, not something the user\n * did. A client reading this hides that provider's native button instead of\n * asking the user to try again.\n *\n * Split out of ValidationError because the other native-enrollment refusal\n * (linking to an account whose email the provider never verified) needs a\n * different response from the app, and one code cannot ask for two.\n */\nexport class NativeSignInUnsupportedError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This provider does not support native id_token sign-in.',\n details: data.details,\n });\n this.name = 'NativeSignInUnsupportedError';\n }\n}\n\n/**\n * Invalid Signup Link Error (400)\n *\n * Thrown when an emailed signup confirmation link is unknown, expired, already\n * consumed, or superseded by a newer request for the same address.\n *\n * One error for all four states, on purpose. Distinguishing \"expired\" from\n * \"unknown\" tells a caller holding a random token whether it named a real\n * pending signup, which is exactly the enumeration the request step avoids. The\n * specific reason is logged.\n */\nexport class InvalidSignupLinkError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This signup link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'InvalidSignupLinkError';\n }\n}\n\n/**\n * Invalid Signup Setup Session Error (401)\n *\n * Thrown when the password-setup session backing a verified-email signup is\n * missing, unknown, expired, superseded or already used.\n *\n * One error for every one of those, on purpose: telling a caller which of them\n * applies tells them whether an address is mid-signup, which is the same\n * enumeration the request step is careful not to leak.\n */\nexport class InvalidSignupSetupSessionError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Password setup session is invalid or has expired. Start the signup again.',\n details: data.details,\n });\n this.name = 'InvalidSignupSetupSessionError';\n }\n}\n\n/**\n * Password Reset Link Error (401)\n *\n * Thrown when an emailed password reset link is unknown, expired, already\n * consumed, superseded by a newer request, or belongs to an account that is no\n * longer active.\n *\n * One error for every one of those, on purpose. Distinguishing \"expired\" from\n * \"unknown\" tells a caller holding a random token whether it named a real\n * pending reset, which is exactly the enumeration the request step avoids. The\n * specific reason is logged.\n */\nexport class PasswordResetLinkError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This password reset link is no longer valid. Request a new one.',\n details: data.details,\n });\n this.name = 'PasswordResetLinkError';\n }\n}\n\n/**\n * Password Reset Session Error (401)\n *\n * Thrown when the password-setup session backing a reset is missing, unknown,\n * expired, superseded or already used.\n *\n * One error for every one of those, for the same reason the link error is one\n * error: which of them applies tells a caller whether an account is mid-reset,\n * and that is the enumeration the request step is careful not to leak.\n */\nexport class PasswordResetSessionError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Password reset session is invalid or has expired. Request a new link.',\n details: data.details,\n });\n this.name = 'PasswordResetSessionError';\n }\n}\n\n/**\n * Unverified Email Link Error (400)\n *\n * Thrown when a social identity carries an email that already belongs to an\n * account, but the provider never verified it. Linking on an unverified email\n * is account takeover, so the refusal stands and the user is sent to a path\n * that proves the address.\n *\n * This says an account exists for that address. It is not a leak introduced\n * here: the message this replaces already stated the same fact in prose, and\n * the paths that must not disclose account existence (password login, deletion\n * re-auth, verification issuance) answer uniformly and are untouched.\n */\nexport class UnverifiedEmailLinkError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'Cannot link to existing account with unverified email. Please verify your email with the provider first.',\n details: data.details,\n });\n this.name = 'UnverifiedEmailLinkError';\n }\n}\n\n/**\n * Verification Token Purpose Mismatch Error (400)\n *\n * Thrown when verification token purpose doesn't match expected purpose\n */\nexport class VerificationTokenPurposeMismatchError extends ValidationError\n{\n constructor(data: { expected?: string; actual?: string; message?: string; details?: Record<string, any> } = {})\n {\n const expected = data.expected || 'unknown';\n const actual = data.actual || 'unknown';\n super({\n message: data.message || `Verification token is for ${actual}, but ${expected} was expected`,\n details: { expected, actual, ...data.details },\n });\n this.name = 'VerificationTokenPurposeMismatchError';\n }\n}\n\n/**\n * Verification Token Target Mismatch Error (400)\n *\n * Thrown when verification token target doesn't match provided email/phone\n */\nexport class VerificationTokenTargetMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Verification token does not match provided email/phone',\n details: data.details,\n });\n this.name = 'VerificationTokenTargetMismatchError';\n }\n}\n\n/**\n * Reserved Username Error (400)\n *\n * Thrown when trying to use a reserved/prohibited username\n */\nexport class ReservedUsernameError extends ValidationError\n{\n constructor(data: { username?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This username is reserved',\n details: { username: data.username, ...data.details },\n });\n this.name = 'ReservedUsernameError';\n }\n}\n\n/**\n * Username Already Taken Error (409)\n *\n * Thrown when trying to set a username that is already in use\n */\nexport class UsernameAlreadyTakenError extends ConflictError\n{\n constructor(data: { username?: string; message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Username is already taken',\n details: { username: data.username, ...data.details },\n });\n this.name = 'UsernameAlreadyTakenError';\n }\n}\n\n/**\n * Insufficient Permissions Error (403)\n *\n * Thrown when user lacks required permissions for the operation\n */\nexport class InsufficientPermissionsError extends ForbiddenError\n{\n constructor(data: { requiredPermissions?: string[]; message?: string; details?: Record<string, any> } = {})\n {\n const requiredPermissions = data.requiredPermissions || [];\n super({\n message: data.message || `Missing required permissions: ${requiredPermissions.join(', ')}`,\n details: { requiredPermissions, ...data.details },\n });\n this.name = 'InsufficientPermissionsError';\n }\n}\n\n/**\n * Insufficient Role Error (403)\n *\n * Thrown when user lacks required role for the operation\n */\nexport class InsufficientRoleError extends ForbiddenError\n{\n constructor(data: { requiredRoles?: string[]; message?: string; details?: Record<string, any> } = {})\n {\n const requiredRoles = data.requiredRoles || [];\n super({\n message: data.message || `Required roles: ${requiredRoles.join(', ')}`,\n details: { requiredRoles, ...data.details },\n });\n this.name = 'InsufficientRoleError';\n }\n}\n\n/**\n * Passkey Challenge Error (401)\n *\n * Thrown when the challenge a WebAuthn ceremony presents is unknown, expired,\n * already spent, minted for the other ceremony, or minted for another account.\n *\n * One error for all five, on purpose. Telling a caller which applies tells them\n * whether a challenge they did not mint exists and what it was for, and the\n * remedy is the same in every case: start the ceremony again.\n */\nexport class PasskeyChallengeError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This passkey challenge is no longer valid. Try again.',\n details: data.details,\n });\n this.name = 'PasskeyChallengeError';\n }\n}\n\n/**\n * Passkey Verification Error (401)\n *\n * Thrown when an assertion or attestation does not verify: wrong origin, wrong\n * rpId, a bad signature, a regressed signature counter — or, on login, a\n * credential that is unknown or has been revoked.\n *\n * Those last two share this error with the cryptographic failures deliberately.\n * A distinct \"no such passkey\" would answer, to anyone holding a credential id,\n * whether it is enrolled here — and a revoked credential answering differently\n * from an unknown one would say the account once had it.\n */\nexport class PasskeyVerificationError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Passkey verification failed.',\n details: data.details,\n });\n this.name = 'PasskeyVerificationError';\n }\n}\n\n/**\n * Passkey Not Found Error (404)\n *\n * Thrown when a management operation names a passkey the caller does not own,\n * or one already revoked. Every lookup is owner-scoped, so the answer is only\n * ever \"not yours\" and says nothing about other accounts.\n */\nexport class PasskeyNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Passkey not found',\n details: data.details,\n });\n this.name = 'PasskeyNotFoundError';\n }\n}\n\n/**\n * Passkey Already Registered Error (409)\n *\n * Thrown when the credential presented for enrollment is already on file for\n * some account — including one that revoked it. A credential id is reserved for\n * good once used, so this is also the answer to re-enrolling one's own revoked\n * passkey.\n */\nexport class PasskeyAlreadyRegisteredError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This passkey is already registered',\n details: data.details,\n });\n this.name = 'PasskeyAlreadyRegisteredError';\n }\n}\n\n/**\n * Recent Authentication Required Error (403)\n *\n * Thrown when enrolling or revoking a passkey from a session that proved itself\n * too long ago and carried no password. Clients branch on `code` to know to\n * prompt for the password rather than to show a generic refusal, so the code is\n * a stable field rather than a message they would have to match on.\n */\nexport class RecentAuthenticationRequiredError extends ForbiddenError\n{\n readonly code = 'RECENT_AUTH_REQUIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Confirm it is you before changing passkeys. Sign in again or send your current password.',\n details: data.details,\n });\n this.name = 'RecentAuthenticationRequiredError';\n }\n}\n\n/**\n * Last Recovery Credential Error (409)\n *\n * Thrown when revoking a passkey would leave the account with no way back in:\n * no other live passkey, no password, and no linked social account. There is no\n * password reset in this package, so that state is not recoverable by support\n * either — the refusal is the only thing standing between the owner and a\n * locked account.\n *\n * Clients branch on `code` to offer \"set a password first\" instead of a generic\n * refusal.\n */\nexport class LastRecoveryCredentialError extends ConflictError\n{\n readonly code = 'LAST_RECOVERY_CREDENTIAL';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'This is the only way you can sign in. Set a password or link a social account before removing it.',\n details: data.details,\n });\n this.name = 'LastRecoveryCredentialError';\n }\n}\n\n/**\n * Session Renewal Required Error (401)\n *\n * Minted by the Next.js proxy, not by the backend: a bound session whose key has\n * run out, on a request the proxy therefore does not forward. The browser's\n * answer is to run the passkey ceremony `renewSession()` wraps and retry, which\n * is the one thing a copied cookie cannot do.\n *\n * Registered here so the proxy's 401 arrives as this class rather than as a bare\n * `ApiError` — the refusal is one an app branches on, and `err instanceof` is\n * how every other branch in this package is written.\n */\nexport class SessionRenewalRequiredError extends UnauthorizedError\n{\n readonly code = 'SESSION_RENEWAL_REQUIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This session needs renewing. Confirm with your passkey to continue.',\n details: data.details,\n });\n this.name = 'SessionRenewalRequiredError';\n }\n}\n\n/**\n * Session Renewal Refused Error (401)\n *\n * The one answer `session/renew/options` and `session/renew/verify` give to every\n * refusal: a key id that names nothing, someone else's key, an unbound key, a\n * revoked key, a key past its renewal grace, an inactive account, a spent\n * challenge, an assertion that did not verify, a passkey belonging to another\n * account.\n *\n * One answer on purpose. The routes are public — they have to be, since the\n * session they repair is the one that stopped working — and a refusal that\n * varied would tell an unauthenticated caller whether a key id is live, which is\n * exactly what the cookie-copying adversary holds and would want confirmed.\n */\nexport class SessionRenewalRefusedError extends UnauthorizedError\n{\n readonly code = 'SESSION_RENEWAL_REFUSED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This session cannot be renewed. Sign in again.',\n details: data.details,\n });\n this.name = 'SessionRenewalRefusedError';\n }\n}\n\n/**\n * Session Context Changed Error (401)\n *\n * Minted by the Next.js proxy: a bound session presented from a different\n * browser family than the one it was sealed from. Browsers do not share cookie\n * jars, so a session that moves between two of them moved because somebody\n * copied it — this is the only defence that acts before the bound key runs out,\n * and it is the reason the three session cookies are cleared with the refusal.\n *\n * Only for bound sessions, and only when the request carried a `user-agent` at\n * all. An absent one is no signal rather than a different family: a server\n * component calling the RPC proxy sends none.\n */\nexport class SessionContextChangedError extends UnauthorizedError\n{\n readonly code = 'SESSION_CONTEXT_CHANGED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This session was started in a different browser. Sign in again.',\n details: data.details,\n });\n this.name = 'SessionContextChangedError';\n }\n}\n\n/**\n * Session Binding Unavailable Error (400)\n *\n * Thrown when an account asks to bind its session on a deployment where the\n * backend cannot tell a request through the trusted Next.js proxy from a direct\n * one — `proxy-guard` unconfigured, so `clientType` is never `'web'`.\n *\n * A configuration refusal rather than a security one, which is why it is a 400\n * and why the message names what to set: with nothing to distinguish the proxy,\n * every key would be registered unbound and the setting would be a switch that\n * reports success and protects nothing.\n */\nexport class SessionBindingUnavailableError extends BadRequestError\n{\n readonly code = 'SESSION_BINDING_UNAVAILABLE';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'Session binding needs a deployment where the backend can recognise the Next.js proxy. '\n + 'Configure proxy-guard (SPFN_PROXY_SIGNATURE_KEYS) and try again.',\n details: data.details,\n });\n this.name = 'SessionBindingUnavailableError';\n }\n}\n\n/**\n * Session Reseal Failed Error (500)\n *\n * Minted by the Next.js proxy when a binding change committed on the backend but\n * the session cookie could not be re-sealed to match it.\n *\n * Answered instead of the route's 200, which is the point: the setting has moved\n * and the cookie has not, and the two disagreeing is the state the whole feature\n * is built to avoid — a bound key with a cookie that says unbound is cleared as\n * an ordinary expired session a day later, and an unbound key with a cookie that\n * says bound asks for a renewal the backend will refuse. The three session\n * cookies go with this refusal, so the repair is a sign-in, which mints a cookie\n * that agrees with the row.\n */\nexport class SessionResealFailedError extends InternalServerError\n{\n readonly code = 'SESSION_RESEAL_FAILED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message\n || 'The setting was changed but this session could not be updated. Sign in again.',\n details: data.details,\n });\n this.name = 'SessionResealFailedError';\n }\n}\n\n/**\n * Passkey Config Error (500)\n *\n * Thrown at boot when the passkey relying-party configuration cannot be honoured\n * — an origin that is not https outside localhost, an origin off the rpId, an\n * unsupported user-verification value.\n *\n * A refusal at boot rather than at the first ceremony: every one of these makes\n * every passkey operation fail, and the drift is between environments, so the\n * deploy that introduces it is where it has to surface.\n */\nexport class PasskeyConfigError extends HttpError\n{\n constructor(data: { message: string; details?: Record<string, any> })\n {\n super({\n message: data.message,\n statusCode: 500,\n details: data.details,\n });\n this.name = 'PasskeyConfigError';\n }\n}\n\n/**\n * OAuth2 Unknown Client Error (400)\n *\n * Thrown by the API authorize endpoints when `client_id` names no registered\n * client. One of the two refusals that must NOT be turned into a redirect: with\n * no client there is no registered redirect URI, so the only place left to send\n * the error is the one the request supplied — which is exactly the open redirect\n * this rule exists to close. The consent screen shows it instead.\n */\nexport class OAuth2UnknownClientError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Unknown OAuth client',\n details: { error: 'unknown_client', ...data.details },\n });\n this.name = 'OAuth2UnknownClientError';\n }\n}\n\n/**\n * OAuth2 Redirect URI Mismatch Error (400)\n *\n * Thrown when `redirect_uri` is not one the client registered. The second\n * non-redirectable refusal, for the same reason as the first: redirecting the\n * error to an unregistered URI is the attack.\n */\nexport class OAuth2RedirectUriMismatchError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'redirect_uri does not match a registered URI for this client',\n details: { error: 'redirect_uri_mismatch', ...data.details },\n });\n this.name = 'OAuth2RedirectUriMismatchError';\n }\n}\n\n/**\n * OAuth2 Authorize Redirect Error (400)\n *\n * Every other authorize-time refusal — `invalid_request`, `invalid_scope`,\n * `invalid_target`, `access_denied`. The client and its redirect URI are both\n * known by the time these are decided, so RFC 6749 §4.1.2.1 says the error goes\n * back to the client as query parameters on that URI rather than to the person.\n *\n * The API cannot perform that redirect — it is answering the web app's consent\n * handler, not the browser — so it carries the pieces in `details` and the\n * handler builds the 302. `redirectUri` is the registered-and-matched value, not\n * the raw parameter, which is what makes it safe to send somebody to.\n */\nexport class OAuth2AuthorizeRedirectError extends ValidationError\n{\n constructor(data: {\n error: string;\n redirectUri: string;\n state?: string;\n message?: string;\n details?: Record<string, any>;\n })\n {\n super({\n message: data.message || `OAuth authorize request refused: ${data.error}`,\n details: {\n error: data.error,\n redirectUri: data.redirectUri,\n state: data.state,\n ...data.details,\n },\n });\n this.name = 'OAuth2AuthorizeRedirectError';\n }\n}\n\n/**\n * OAuth2 Grant Not Found Error (404)\n *\n * Thrown by `DELETE /_auth/oauth2/grants/:id` when the caller owns no live grant\n * of that id. A grant belonging to somebody else answers the same way as one\n * that never existed — the id is a number in a URL, and telling the two apart\n * would let anyone count other people's connected clients.\n */\nexport class OAuth2GrantNotFoundError extends NotFoundError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({ message: data.message || 'No such connected application', details: data.details });\n this.name = 'OAuth2GrantNotFoundError';\n }\n}\n\n/**\n * MFA Already Enrolled Error (409)\n *\n * Thrown when `totp/enroll` is called on an account whose TOTP is already\n * confirmed. Replacing a working second factor is `disable` followed by a fresh\n * enrolment, both step-up gated — an enrol that quietly overwrote a confirmed\n * secret would be a way to swap someone's authenticator for your own.\n */\nexport class MfaAlreadyEnrolledError extends ConflictError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'A second factor is already enrolled on this account',\n details: data.details,\n });\n this.name = 'MfaAlreadyEnrolledError';\n }\n}\n\n/**\n * MFA Not Enrolled Error (400)\n *\n * Thrown when a call needs an enrolment that is not there: `totp/confirm` with\n * no pending secret — including the row its own five failed attempts deleted —\n * or `recovery/regenerate` on an account with no second factor. `disable` is\n * deliberately not one of them; it answers 204 either way, because \"make sure\n * MFA is off\" has already succeeded.\n */\nexport class MfaNotEnrolledError extends ValidationError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'No second-factor enrolment is in progress on this account',\n details: data.details,\n });\n this.name = 'MfaNotEnrolledError';\n }\n}\n\n/**\n * MFA Verification Failed Error (401)\n *\n * Thrown when a submitted code does not verify: a wrong or stale TOTP, a code\n * from a step already spent, a recovery code that is used, from an older\n * generation or another account's, or an assertion from a passkey the owner\n * never marked as a second factor.\n *\n * One body for all of them. Which one applies describes state the caller is\n * guessing at, and the remedy — look at the authenticator again — is the same.\n */\nexport class MfaVerificationFailedError extends UnauthorizedError\n{\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'That code did not verify',\n details: data.details,\n });\n this.name = 'MfaVerificationFailedError';\n }\n}\n\n/**\n * Step Up Required Error (403)\n *\n * Thrown when an enrolled account asks for a sensitive change from a device\n * whose second factor was last verified longer ago than the step-up window. A\n * stolen session alone therefore cannot change a password, sign every device\n * out, or take the second factor off.\n *\n * 403 and not 401, on the same reasoning as `RecentAuthenticationRequiredError`,\n * which it sits beside: a 401 on an authenticated route is what a web client\n * reads as \"the session is gone\", so it would sign the user out instead of\n * asking for a code. Clients branch on `code` to send the user to\n * `POST /_auth/mfa/step-up` and retry.\n */\nexport class StepUpRequiredError extends ForbiddenError\n{\n readonly code = 'STEP_UP_REQUIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'Confirm your second factor before making this change.',\n details: data.details,\n });\n this.name = 'StepUpRequiredError';\n }\n}\n\n/**\n * Session Pending Mismatch Error (401)\n *\n * Minted by the Next.js proxy: a second-factor verification succeeded at the\n * backend, but the pending cookie this browser is holding was baked for a\n * different challenge or a different device key.\n *\n * The comparison is the whole reason the cookie exists. Without it the proxy\n * would seal whatever private key it happens to be holding around whatever key\n * the verification activated — a person who starts a social login in one tab\n * while a password step-up is outstanding in another would get a session signed\n * with the wrong key, and `authenticate` would refuse every request it made.\n *\n * The key really is active by the time this is raised: the backend accepted the\n * proof and this browser simply cannot prove it is the one that asked. Signing\n * in again is the remedy, and it is a cheap one.\n */\nexport class SessionPendingMismatchError extends UnauthorizedError\n{\n readonly code = 'SESSION_PENDING_MISMATCH';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'This browser did not start that sign-in. Sign in again.',\n details: data.details,\n });\n this.name = 'SessionPendingMismatchError';\n }\n}\n\n/**\n * Session Pending Expired Error (401)\n *\n * Minted by the Next.js proxy: a second-factor verification succeeded and there\n * is no pending cookie to seal a session from — ten minutes passed, or the\n * browser that finished the step-up is not the browser that started it.\n *\n * Told apart from a mismatch on purpose. This one is the ordinary way a person\n * meets the end of the window, and the message can say so; a mismatch is a\n * cookie that is present and wrong, which is worth a different line in a log.\n */\nexport class SessionPendingExpiredError extends UnauthorizedError\n{\n readonly code = 'SESSION_PENDING_EXPIRED';\n\n constructor(data: { message?: string; details?: Record<string, any> } = {})\n {\n super({\n message: data.message || 'That sign-in took too long. Sign in again.',\n details: data.details,\n });\n this.name = 'SessionPendingExpiredError';\n }\n}\n\n/**\n * MFA Config Error (500)\n *\n * Thrown when the at-rest keyring cannot serve a second factor:\n * `SPFN_AUTH_TOKEN_ENCRYPTION_KEYS` is unset, or a stored secret names a key id\n * that has been dropped from it.\n *\n * Deliberately not the 401 a wrong code gets. The two have nothing in common: a\n * wrong code is one person looking at the wrong line of their authenticator,\n * and a broken keyring is every enrolled user locked out at once by a deploy.\n * An operator has to be able to tell them apart from the response alone.\n */\nexport class MfaConfigError extends HttpError\n{\n constructor(data: { message: string; details?: Record<string, any> })\n {\n super({\n message: data.message,\n statusCode: 500,\n details: data.details,\n });\n this.name = 'MfaConfigError';\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
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 LoginResult, e as StartDeviceAuthResult, D as DeviceAuthInfoResult, F as FinishPasskeyEnrollmentResult, f as PasskeySummary, T as TotpEnrolmentResult, g as ConfirmTotpResult, M as MfaStatus, h as RotateKeyResult, K as KeySummary, i as RevokeAllKeysResult, I as IssueOneTimeTokenResult, O as OAuthStartResult, j as OAuthNativeResult, U as UserProfile, k as ProfileInfo, l as OAuth2ConsentView, n as OAuth2AuthorizationCodeIssued, o as OAuth2GrantSummary } from './machine-principals-CaEFq61K.js';
3
- export { A as AuthInitOptions, p as AuthSession, q as PERMISSION_CATEGORIES, r as PermissionCategory, V as VERIFICATION_PURPOSES, s as VERIFICATION_TARGET_TYPES, t as VerificationPurpose, u as VerificationTargetType } from './machine-principals-CaEFq61K.js';
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 LoginResult, e as StartDeviceAuthResult, D as DeviceAuthInfoResult, F as FinishPasskeyEnrollmentResult, f as PasskeySummary, T as TotpEnrolmentResult, g as ConfirmTotpResult, M as MfaStatus, V as VerifyMfaChallengeResult, h as RotateKeyResult, K as KeySummary, i as RevokeAllKeysResult, j as SessionBindingResult, k as SessionRenewResult, I as IssueOneTimeTokenResult, O as OAuthStartResult, l as OAuthFinalizeResponse, n as OAuthNativeResult, U as UserProfile, o as ProfileInfo, p as OAuth2ConsentView, q as OAuth2AuthorizationCodeIssued, r as OAuth2GrantSummary } from './machine-principals-CdEgxOB1.js';
3
+ export { A as AuthInitOptions, s as AuthSession, t as PERMISSION_CATEGORIES, u as PermissionCategory, v as VERIFICATION_PURPOSES, w as VERIFICATION_TARGET_TYPES, x as VerificationPurpose, y as VerificationTargetType } from './machine-principals-CdEgxOB1.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
- 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, S as SOCIAL_PROVIDERS, j as SocialProvider, U as USER_STATUSES, k as UserStatus } from './types-DYyhze28.js';
7
+ 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, S as SessionBindingType, l as SocialProvider, U as USER_STATUSES, m as UserStatus } from './types-CTdoTOxM.js';
8
8
  import * as _sinclair_typebox from '@sinclair/typebox';
9
9
  import 'drizzle-orm/pg-core';
10
10
  import '@spfn/core/event';
@@ -180,7 +180,7 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
180
180
  deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
181
181
  platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
182
182
  }>;
183
- }, RegisterResult>;
183
+ }, LoginResult>;
184
184
  login: _spfn_core_route.RouteDef<{
185
185
  body: _sinclair_typebox.TObject<{
186
186
  email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
@@ -218,7 +218,10 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
218
218
  } | {
219
219
  email?: string | undefined;
220
220
  phone?: string | undefined;
221
+ sessionBinding?: "none" | "passkey" | undefined;
222
+ keyExpiresAtMillis?: number | undefined;
221
223
  status: "approved";
224
+ mfaRequired: boolean;
222
225
  userId: string;
223
226
  publicId: string;
224
227
  passwordChangeRequired: boolean;
@@ -322,6 +325,19 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
322
325
  mfaStepUpOptions: _spfn_core_route.RouteDef<{
323
326
  body: _sinclair_typebox.TObject<{}>;
324
327
  }, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
328
+ mfaVerify: _spfn_core_route.RouteDef<{
329
+ body: _sinclair_typebox.TObject<{
330
+ challenge: _sinclair_typebox.TString;
331
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
332
+ recoveryCode: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
333
+ response: _sinclair_typebox.TOptional<_sinclair_typebox.TUnknown>;
334
+ }>;
335
+ }, {}, VerifyMfaChallengeResult>;
336
+ mfaVerifyOptions: _spfn_core_route.RouteDef<{
337
+ body: _sinclair_typebox.TObject<{
338
+ challenge: _sinclair_typebox.TString;
339
+ }>;
340
+ }, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
325
341
  logout: _spfn_core_route.RouteDef<{}, {}, void>;
326
342
  rotateKey: _spfn_core_route.RouteDef<{}, {
327
343
  body: _sinclair_typebox.TObject<{
@@ -394,6 +410,32 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
394
410
  phoneVerified: boolean;
395
411
  hasPassword: boolean;
396
412
  }>;
413
+ setSessionBinding: _spfn_core_route.RouteDef<{
414
+ body: _sinclair_typebox.TObject<{
415
+ mode: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"passkey">, _sinclair_typebox.TLiteral<"none">]>;
416
+ response: _sinclair_typebox.TOptional<_sinclair_typebox.TUnknown>;
417
+ currentPassword: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
418
+ }>;
419
+ }, {}, SessionBindingResult>;
420
+ getSessionBinding: _spfn_core_route.RouteDef<{}, {}, SessionBindingResult>;
421
+ sessionBindingDisableOptions: _spfn_core_route.RouteDef<{
422
+ body: _sinclair_typebox.TObject<{}>;
423
+ }, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
424
+ sessionRenewOptions: _spfn_core_route.RouteDef<{
425
+ body: _sinclair_typebox.TObject<{}>;
426
+ }, {}, _simplewebauthn_server.PublicKeyCredentialRequestOptionsJSON>;
427
+ sessionRenewVerify: _spfn_core_route.RouteDef<{
428
+ body: _sinclair_typebox.TObject<{
429
+ response: _sinclair_typebox.TUnknown;
430
+ }>;
431
+ }, {
432
+ body: _sinclair_typebox.TObject<{
433
+ publicKey: _sinclair_typebox.TString;
434
+ keyId: _sinclair_typebox.TString;
435
+ fingerprint: _sinclair_typebox.TString;
436
+ algorithm: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>>;
437
+ }>;
438
+ }, SessionRenewResult>;
397
439
  issueOneTimeToken: _spfn_core_route.RouteDef<{}, {}, IssueOneTimeTokenResult>;
398
440
  requestAccountDeletion: _spfn_core_route.RouteDef<{
399
441
  body: _sinclair_typebox.TObject<{
@@ -451,16 +493,12 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
451
493
  }>;
452
494
  oauthFinalize: _spfn_core_route.RouteDef<{
453
495
  body: _sinclair_typebox.TObject<{
454
- userId: _sinclair_typebox.TString;
455
- keyId: _sinclair_typebox.TString;
496
+ userId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
497
+ keyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
498
+ mfaChallenge: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
456
499
  returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
457
500
  }>;
458
- }, {}, {
459
- success: boolean;
460
- userId: string;
461
- keyId: string;
462
- returnUrl: string;
463
- }>;
501
+ }, {}, OAuthFinalizeResponse>;
464
502
  oauthProviderStart: _spfn_core_route.RouteDef<{
465
503
  params: _sinclair_typebox.TObject<{
466
504
  provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "apple" | "github" | "kakao" | "naver" | "superself">[]>;
@@ -670,6 +708,8 @@ declare const authApi: _spfn_core_nextjs.Client<_spfn_core_route.Router<{
670
708
  emailVerifiedAt: Date | null;
671
709
  phoneVerifiedAt: Date | null;
672
710
  keyEpoch: number;
711
+ sessionBinding: "none" | "passkey";
712
+ sessionBindingChangedAt: Date | null;
673
713
  lastLoginAt: Date | null;
674
714
  }>;
675
715
  updateLocale: _spfn_core_route.RouteDef<{
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({
@@ -451,6 +503,26 @@ var StepUpRequiredError = class extends ForbiddenError {
451
503
  this.name = "StepUpRequiredError";
452
504
  }
453
505
  };
506
+ var SessionPendingMismatchError = class extends UnauthorizedError {
507
+ code = "SESSION_PENDING_MISMATCH";
508
+ constructor(data = {}) {
509
+ super({
510
+ message: data.message || "This browser did not start that sign-in. Sign in again.",
511
+ details: data.details
512
+ });
513
+ this.name = "SessionPendingMismatchError";
514
+ }
515
+ };
516
+ var SessionPendingExpiredError = class extends UnauthorizedError {
517
+ code = "SESSION_PENDING_EXPIRED";
518
+ constructor(data = {}) {
519
+ super({
520
+ message: data.message || "That sign-in took too long. Sign in again.",
521
+ details: data.details
522
+ });
523
+ this.name = "SessionPendingExpiredError";
524
+ }
525
+ };
454
526
  var MfaConfigError = class extends HttpError {
455
527
  constructor(data) {
456
528
  super({
@@ -508,6 +580,11 @@ authErrorRegistry.append([
508
580
  RecentAuthenticationRequiredError,
509
581
  LastRecoveryCredentialError,
510
582
  PasskeyConfigError,
583
+ SessionBindingUnavailableError,
584
+ SessionRenewalRequiredError,
585
+ SessionRenewalRefusedError,
586
+ SessionContextChangedError,
587
+ SessionResealFailedError,
511
588
  OAuth2UnknownClientError,
512
589
  OAuth2RedirectUriMismatchError,
513
590
  OAuth2AuthorizeRedirectError,
@@ -516,7 +593,9 @@ authErrorRegistry.append([
516
593
  MfaNotEnrolledError,
517
594
  MfaVerificationFailedError,
518
595
  StepUpRequiredError,
519
- MfaConfigError
596
+ MfaConfigError,
597
+ SessionPendingMismatchError,
598
+ SessionPendingExpiredError
520
599
  ]);
521
600
 
522
601
  // src/generated/route-map.ts
@@ -552,8 +631,15 @@ var routeMap = {
552
631
  mfaMarkPasskey: { method: "POST", path: "/_auth/mfa/passkey/mark" },
553
632
  mfaRegenerateRecoveryCodes: { method: "POST", path: "/_auth/mfa/recovery/regenerate" },
554
633
  mfaStatus: { method: "GET", path: "/_auth/mfa/status" },
634
+ mfaVerify: { method: "POST", path: "/_auth/mfa/verify" },
635
+ mfaVerifyOptions: { method: "POST", path: "/_auth/mfa/verify/options" },
555
636
  mfaStepUp: { method: "POST", path: "/_auth/mfa/step-up" },
556
637
  mfaStepUpOptions: { method: "POST", path: "/_auth/mfa/step-up/options" },
638
+ setSessionBinding: { method: "POST", path: "/_auth/session/binding" },
639
+ getSessionBinding: { method: "GET", path: "/_auth/session/binding" },
640
+ sessionBindingDisableOptions: { method: "POST", path: "/_auth/session/binding/disable/options" },
641
+ sessionRenewOptions: { method: "POST", path: "/_auth/session/renew/options" },
642
+ sessionRenewVerify: { method: "POST", path: "/_auth/session/renew/verify" },
557
643
  passkeyRegisterOptions: { method: "POST", path: "/_auth/passkeys/register/options" },
558
644
  passkeyRegisterVerify: { method: "POST", path: "/_auth/passkeys/register/verify" },
559
645
  passkeyLoginOptions: { method: "POST", path: "/_auth/passkeys/login/options" },
@@ -740,6 +826,7 @@ var BUILTIN_ROLE_PERMISSIONS = {
740
826
  var KEY_ALGORITHM = ["ES256", "RS256"];
741
827
  var KEY_PLATFORM = ["ios", "android", "web", "desktop"];
742
828
  var KEY_DEVICE_NAME_MAX_LENGTH = 64;
829
+ var SESSION_BINDINGS = ["none", "passkey"];
743
830
  var INVITATION_STATUSES = ["pending", "accepted", "expired", "cancelled"];
744
831
  var USER_STATUSES = ["active", "inactive", "suspended", "pending_deletion", "deleted"];
745
832
  var SOCIAL_PROVIDERS = ["google", "apple", "github", "kakao", "naver", "superself"];
@@ -3400,11 +3487,25 @@ var DeviceAuthPollResponseSchema = Type.Union([
3400
3487
  }),
3401
3488
  Type.Object({
3402
3489
  status: Type.Literal("approved"),
3490
+ // The `LoginResult` discriminant, carried because the approved branch is
3491
+ // a `LoginResult` spread whole (#95). Always false here: a device-code
3492
+ // approval is the owner saying yes on a device that is already signed
3493
+ // in, which is itself a second factor, so this channel never steps up
3494
+ // and never carries a challenge.
3495
+ mfaRequired: Type.Boolean(),
3403
3496
  userId: Type.String(),
3404
3497
  publicId: Type.String(),
3405
3498
  email: Type.Optional(Type.String()),
3406
3499
  phone: Type.Optional(Type.String()),
3407
- passwordChangeRequired: Type.Boolean()
3500
+ passwordChangeRequired: Type.Boolean(),
3501
+ // The approved branch is a `LoginResult` spread whole, so it carries the
3502
+ // binding fields a sign-in can carry (#97). In practice it never does: a
3503
+ // waiting device polls the backend directly, and a key is bound only on a
3504
+ // request that reached it through the trusted Next.js proxy. Declared
3505
+ // anyway, because the branch is whatever the login answered and the two
3506
+ // must not be able to drift apart.
3507
+ sessionBinding: Type.Optional(Type.Union(SESSION_BINDINGS.map((mode) => Type.Literal(mode)))),
3508
+ keyExpiresAtMillis: Type.Optional(Type.Integer())
3408
3509
  })
3409
3510
  ], {
3410
3511
  description: "Pending, or the login the approval produced"