@effect-auth/core 0.1.0-alpha.16 → 0.1.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +307 -133
- package/dist/AbuseProtection.d.ts +100 -0
- package/dist/AbuseProtection.d.ts.map +1 -0
- package/dist/AbuseProtection.js +71 -0
- package/dist/AbuseProtection.js.map +1 -0
- package/dist/AccessGrant.d.ts +344 -0
- package/dist/AccessGrant.d.ts.map +1 -0
- package/dist/AccessGrant.js +687 -0
- package/dist/AccessGrant.js.map +1 -0
- package/dist/ApiKey.d.ts +0 -12
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +36 -27
- package/dist/ApiKey.js.map +1 -1
- package/dist/Assurance.d.ts +415 -0
- package/dist/Assurance.d.ts.map +1 -0
- package/dist/Assurance.js +764 -0
- package/dist/Assurance.js.map +1 -0
- package/dist/AtomicPlanExecutor.d.ts +28 -0
- package/dist/AtomicPlanExecutor.d.ts.map +1 -0
- package/dist/AtomicPlanExecutor.js +5 -0
- package/dist/AtomicPlanExecutor.js.map +1 -0
- package/dist/AuditLog.d.ts +2314 -52
- package/dist/AuditLog.d.ts.map +1 -1
- package/dist/AuditLog.js +511 -33
- package/dist/AuditLog.js.map +1 -1
- package/dist/AuthFlow.d.ts +128 -38
- package/dist/AuthFlow.d.ts.map +1 -1
- package/dist/AuthFlow.js +611 -263
- package/dist/AuthFlow.js.map +1 -1
- package/dist/AuthRateLimit.d.ts +96 -0
- package/dist/AuthRateLimit.d.ts.map +1 -0
- package/dist/AuthRateLimit.js +212 -0
- package/dist/AuthRateLimit.js.map +1 -0
- package/dist/Challenge.d.ts +0 -3
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +1 -4
- package/dist/Challenge.js.map +1 -1
- package/dist/Client.d.ts +205 -10
- package/dist/Client.d.ts.map +1 -1
- package/dist/Client.js +397 -16
- package/dist/Client.js.map +1 -1
- package/dist/CloudflareTurnstile.d.ts +28 -0
- package/dist/CloudflareTurnstile.d.ts.map +1 -0
- package/dist/CloudflareTurnstile.js +205 -0
- package/dist/CloudflareTurnstile.js.map +1 -0
- package/dist/Crypto.d.ts +0 -3
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +1 -4
- package/dist/Crypto.js.map +1 -1
- package/dist/DelegatedAccessStorageMigrations.d.ts +7 -0
- package/dist/DelegatedAccessStorageMigrations.d.ts.map +1 -0
- package/dist/DelegatedAccessStorageMigrations.js +159 -0
- package/dist/DelegatedAccessStorageMigrations.js.map +1 -0
- package/dist/DevEmail.d.ts +44 -0
- package/dist/DevEmail.d.ts.map +1 -0
- package/dist/DevEmail.js +115 -0
- package/dist/DevEmail.js.map +1 -0
- package/dist/DevelopmentSeed.d.ts +47 -0
- package/dist/DevelopmentSeed.d.ts.map +1 -0
- package/dist/DevelopmentSeed.js +337 -0
- package/dist/DevelopmentSeed.js.map +1 -0
- package/dist/DisposableEmailDomains.d.ts +19 -0
- package/dist/DisposableEmailDomains.d.ts.map +1 -0
- package/dist/DisposableEmailDomains.js +85 -0
- package/dist/DisposableEmailDomains.js.map +1 -0
- package/dist/DomainVerification.d.ts +0 -9
- package/dist/DomainVerification.d.ts.map +1 -1
- package/dist/DomainVerification.js +36 -22
- package/dist/DomainVerification.js.map +1 -1
- package/dist/DrizzleBunSqliteStorage.d.ts +18 -0
- package/dist/DrizzleBunSqliteStorage.d.ts.map +1 -0
- package/dist/DrizzleBunSqliteStorage.js +11 -0
- package/dist/DrizzleBunSqliteStorage.js.map +1 -0
- package/dist/DrizzleD1SqliteStorage.d.ts +4 -4
- package/dist/DrizzleD1SqliteStorage.d.ts.map +1 -1
- package/dist/DrizzleD1SqliteStorage.js +5 -5
- package/dist/DrizzleD1SqliteStorage.js.map +1 -1
- package/dist/DrizzleEffectSqliteStorage.d.ts +13 -4
- package/dist/DrizzleEffectSqliteStorage.d.ts.map +1 -1
- package/dist/DrizzleEffectSqliteStorage.js +71 -4
- package/dist/DrizzleEffectSqliteStorage.js.map +1 -1
- package/dist/DrizzleNodeSqliteStorage.d.ts +18 -0
- package/dist/DrizzleNodeSqliteStorage.d.ts.map +1 -0
- package/dist/DrizzleNodeSqliteStorage.js +11 -0
- package/dist/DrizzleNodeSqliteStorage.js.map +1 -0
- package/dist/DrizzlePostgresStorage.d.ts +26 -0
- package/dist/DrizzlePostgresStorage.d.ts.map +1 -0
- package/dist/DrizzlePostgresStorage.js +14 -0
- package/dist/DrizzlePostgresStorage.js.map +1 -0
- package/dist/EffectQbPostgresDelegatedAccessStorage.d.ts +34 -0
- package/dist/EffectQbPostgresDelegatedAccessStorage.d.ts.map +1 -0
- package/dist/EffectQbPostgresDelegatedAccessStorage.js +499 -0
- package/dist/EffectQbPostgresDelegatedAccessStorage.js.map +1 -0
- package/dist/EffectQbPostgresStorage.d.ts +178 -0
- package/dist/EffectQbPostgresStorage.d.ts.map +1 -0
- package/dist/EffectQbPostgresStorage.js +4637 -0
- package/dist/EffectQbPostgresStorage.js.map +1 -0
- package/dist/EffectQbSqliteDelegatedAccessStorage.d.ts +112 -0
- package/dist/EffectQbSqliteDelegatedAccessStorage.d.ts.map +1 -0
- package/dist/EffectQbSqliteDelegatedAccessStorage.js +602 -0
- package/dist/EffectQbSqliteDelegatedAccessStorage.js.map +1 -0
- package/dist/EffectQbSqliteStorage.d.ts +221 -23
- package/dist/EffectQbSqliteStorage.d.ts.map +1 -1
- package/dist/EffectQbSqliteStorage.js +2064 -135
- package/dist/EffectQbSqliteStorage.js.map +1 -1
- package/dist/EmailAuth.d.ts +65 -0
- package/dist/EmailAuth.d.ts.map +1 -0
- package/dist/EmailAuth.js +171 -0
- package/dist/EmailAuth.js.map +1 -0
- package/dist/EmailIdentityAuth.d.ts +30 -0
- package/dist/EmailIdentityAuth.d.ts.map +1 -0
- package/dist/EmailIdentityAuth.js +142 -0
- package/dist/EmailIdentityAuth.js.map +1 -0
- package/dist/EmailOtp.d.ts +10 -11
- package/dist/EmailOtp.d.ts.map +1 -1
- package/dist/EmailOtp.js +44 -81
- package/dist/EmailOtp.js.map +1 -1
- package/dist/EmailRisk.d.ts +48 -0
- package/dist/EmailRisk.d.ts.map +1 -0
- package/dist/EmailRisk.js +33 -0
- package/dist/EmailRisk.js.map +1 -0
- package/dist/EmailVerification.d.ts +10 -16
- package/dist/EmailVerification.d.ts.map +1 -1
- package/dist/EmailVerification.js +85 -42
- package/dist/EmailVerification.js.map +1 -1
- package/dist/Guard.d.ts +11 -0
- package/dist/Guard.d.ts.map +1 -0
- package/dist/Guard.js +11 -0
- package/dist/Guard.js.map +1 -0
- package/dist/HibpPwnedPasswords.d.ts +56 -0
- package/dist/HibpPwnedPasswords.d.ts.map +1 -0
- package/dist/HibpPwnedPasswords.js +232 -0
- package/dist/HibpPwnedPasswords.js.map +1 -0
- package/dist/HttpApi/AdminPermissionDefinition.d.ts +4 -0
- package/dist/HttpApi/AdminPermissionDefinition.d.ts.map +1 -0
- package/dist/HttpApi/AdminPermissionDefinition.js +4 -0
- package/dist/HttpApi/AdminPermissionDefinition.js.map +1 -0
- package/dist/HttpApi/AdminSecurityTimeline.d.ts +4 -0
- package/dist/HttpApi/AdminSecurityTimeline.d.ts.map +1 -0
- package/dist/HttpApi/AdminSecurityTimeline.js +4 -0
- package/dist/HttpApi/AdminSecurityTimeline.js.map +1 -0
- package/dist/HttpApi/AdminSession.d.ts +4 -0
- package/dist/HttpApi/AdminSession.d.ts.map +1 -0
- package/dist/HttpApi/AdminSession.js +4 -0
- package/dist/HttpApi/AdminSession.js.map +1 -0
- package/dist/HttpApi/AdminTrustedDevice.d.ts +4 -0
- package/dist/HttpApi/AdminTrustedDevice.d.ts.map +1 -0
- package/dist/HttpApi/AdminTrustedDevice.js +4 -0
- package/dist/HttpApi/AdminTrustedDevice.js.map +1 -0
- package/dist/HttpApi/Api.d.ts +939 -884
- package/dist/HttpApi/Api.d.ts.map +1 -1
- package/dist/HttpApi/Api.js +2254 -940
- package/dist/HttpApi/Api.js.map +1 -1
- package/dist/HttpApi/ApiKey.d.ts +4 -0
- package/dist/HttpApi/ApiKey.d.ts.map +1 -0
- package/dist/HttpApi/ApiKey.js +4 -0
- package/dist/HttpApi/ApiKey.js.map +1 -0
- package/dist/HttpApi/Audit.d.ts +6 -0
- package/dist/HttpApi/Audit.d.ts.map +1 -0
- package/dist/HttpApi/Audit.js +10 -0
- package/dist/HttpApi/Audit.js.map +1 -0
- package/dist/HttpApi/ClientApi.d.ts +917 -0
- package/dist/HttpApi/ClientApi.d.ts.map +1 -0
- package/dist/HttpApi/ClientApi.js +101 -0
- package/dist/HttpApi/ClientApi.js.map +1 -0
- package/dist/HttpApi/EmailAuth.d.ts +6 -0
- package/dist/HttpApi/EmailAuth.d.ts.map +1 -0
- package/dist/HttpApi/EmailAuth.js +6 -0
- package/dist/HttpApi/EmailAuth.js.map +1 -0
- package/dist/HttpApi/EmailGuards.d.ts +115 -0
- package/dist/HttpApi/EmailGuards.d.ts.map +1 -0
- package/dist/HttpApi/EmailGuards.js +191 -0
- package/dist/HttpApi/EmailGuards.js.map +1 -0
- package/dist/HttpApi/EmailOtp.d.ts +6 -0
- package/dist/HttpApi/EmailOtp.d.ts.map +1 -0
- package/dist/HttpApi/EmailOtp.js +6 -0
- package/dist/HttpApi/EmailOtp.js.map +1 -0
- package/dist/HttpApi/EmailVerification.d.ts +6 -0
- package/dist/HttpApi/EmailVerification.d.ts.map +1 -0
- package/dist/HttpApi/EmailVerification.js +6 -0
- package/dist/HttpApi/EmailVerification.js.map +1 -0
- package/dist/HttpApi/Endpoints.d.ts +661 -301
- package/dist/HttpApi/Endpoints.d.ts.map +1 -1
- package/dist/HttpApi/Endpoints.js +207 -120
- package/dist/HttpApi/Endpoints.js.map +1 -1
- package/dist/HttpApi/Errors.d.ts +37 -10
- package/dist/HttpApi/Errors.d.ts.map +1 -1
- package/dist/HttpApi/Errors.js +42 -4
- package/dist/HttpApi/Errors.js.map +1 -1
- package/dist/HttpApi/Identity.d.ts +6 -0
- package/dist/HttpApi/Identity.d.ts.map +1 -0
- package/dist/HttpApi/Identity.js +6 -0
- package/dist/HttpApi/Identity.js.map +1 -0
- package/dist/HttpApi/IdentityGuards.d.ts +31 -0
- package/dist/HttpApi/IdentityGuards.d.ts.map +1 -0
- package/dist/HttpApi/IdentityGuards.js +33 -0
- package/dist/HttpApi/IdentityGuards.js.map +1 -0
- package/dist/HttpApi/Jwt.d.ts +4 -0
- package/dist/HttpApi/Jwt.d.ts.map +1 -0
- package/dist/HttpApi/Jwt.js +4 -0
- package/dist/HttpApi/Jwt.js.map +1 -0
- package/dist/HttpApi/JwtDiscovery.d.ts +4 -0
- package/dist/HttpApi/JwtDiscovery.d.ts.map +1 -0
- package/dist/HttpApi/JwtDiscovery.js +4 -0
- package/dist/HttpApi/JwtDiscovery.js.map +1 -0
- package/dist/HttpApi/LoginApproval.d.ts +5 -0
- package/dist/HttpApi/LoginApproval.d.ts.map +1 -0
- package/dist/HttpApi/LoginApproval.js +5 -0
- package/dist/HttpApi/LoginApproval.js.map +1 -0
- package/dist/HttpApi/LoginNotification.d.ts +5 -0
- package/dist/HttpApi/LoginNotification.d.ts.map +1 -0
- package/dist/HttpApi/LoginNotification.js +5 -0
- package/dist/HttpApi/LoginNotification.js.map +1 -0
- package/dist/HttpApi/MagicLink.d.ts +6 -0
- package/dist/HttpApi/MagicLink.d.ts.map +1 -0
- package/dist/HttpApi/MagicLink.js +6 -0
- package/dist/HttpApi/MagicLink.js.map +1 -0
- package/dist/HttpApi/Mfa.d.ts +5 -0
- package/dist/HttpApi/Mfa.d.ts.map +1 -0
- package/dist/HttpApi/Mfa.js +5 -0
- package/dist/HttpApi/Mfa.js.map +1 -0
- package/dist/HttpApi/Middleware.d.ts +26 -0
- package/dist/HttpApi/Middleware.d.ts.map +1 -0
- package/dist/HttpApi/Middleware.js +13 -0
- package/dist/HttpApi/Middleware.js.map +1 -0
- package/dist/HttpApi/OAuth.d.ts +4 -0
- package/dist/HttpApi/OAuth.d.ts.map +1 -0
- package/dist/HttpApi/OAuth.js +4 -0
- package/dist/HttpApi/OAuth.js.map +1 -0
- package/dist/HttpApi/OAuthDeviceAuthorization.d.ts +106 -0
- package/dist/HttpApi/OAuthDeviceAuthorization.d.ts.map +1 -0
- package/dist/HttpApi/OAuthDeviceAuthorization.js +415 -0
- package/dist/HttpApi/OAuthDeviceAuthorization.js.map +1 -0
- package/dist/HttpApi/OAuthProviderAuthorization.d.ts +4 -0
- package/dist/HttpApi/OAuthProviderAuthorization.d.ts.map +1 -0
- package/dist/HttpApi/OAuthProviderAuthorization.js +4 -0
- package/dist/HttpApi/OAuthProviderAuthorization.js.map +1 -0
- package/dist/HttpApi/OAuthToken.d.ts +4 -0
- package/dist/HttpApi/OAuthToken.d.ts.map +1 -0
- package/dist/HttpApi/OAuthToken.js +4 -0
- package/dist/HttpApi/OAuthToken.js.map +1 -0
- package/dist/HttpApi/OidcDiscovery.d.ts +4 -0
- package/dist/HttpApi/OidcDiscovery.d.ts.map +1 -0
- package/dist/HttpApi/OidcDiscovery.js +4 -0
- package/dist/HttpApi/OidcDiscovery.js.map +1 -0
- package/dist/HttpApi/Operations/AdminPermissionDefinition.d.ts +28 -0
- package/dist/HttpApi/Operations/AdminPermissionDefinition.d.ts.map +1 -0
- package/dist/HttpApi/Operations/AdminPermissionDefinition.js +5 -0
- package/dist/HttpApi/Operations/AdminPermissionDefinition.js.map +1 -0
- package/dist/HttpApi/Operations/AdminSession.d.ts +16 -0
- package/dist/HttpApi/Operations/AdminSession.d.ts.map +1 -0
- package/dist/HttpApi/Operations/AdminSession.js +5 -0
- package/dist/HttpApi/Operations/AdminSession.js.map +1 -0
- package/dist/HttpApi/Operations/ApiKey.d.ts +16 -0
- package/dist/HttpApi/Operations/ApiKey.d.ts.map +1 -0
- package/dist/HttpApi/Operations/ApiKey.js +5 -0
- package/dist/HttpApi/Operations/ApiKey.js.map +1 -0
- package/dist/HttpApi/Operations/Discovery.d.ts +19 -0
- package/dist/HttpApi/Operations/Discovery.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Discovery.js +7 -0
- package/dist/HttpApi/Operations/Discovery.js.map +1 -0
- package/dist/HttpApi/Operations/EmailAuth.d.ts +12 -0
- package/dist/HttpApi/Operations/EmailAuth.d.ts.map +1 -0
- package/dist/HttpApi/Operations/EmailAuth.js +5 -0
- package/dist/HttpApi/Operations/EmailAuth.js.map +1 -0
- package/dist/HttpApi/Operations/EmailOtp.d.ts +14 -0
- package/dist/HttpApi/Operations/EmailOtp.d.ts.map +1 -0
- package/dist/HttpApi/Operations/EmailOtp.js +5 -0
- package/dist/HttpApi/Operations/EmailOtp.js.map +1 -0
- package/dist/HttpApi/Operations/EmailVerification.d.ts +14 -0
- package/dist/HttpApi/Operations/EmailVerification.d.ts.map +1 -0
- package/dist/HttpApi/Operations/EmailVerification.js +5 -0
- package/dist/HttpApi/Operations/EmailVerification.js.map +1 -0
- package/dist/HttpApi/Operations/HttpOperation.d.ts +4 -0
- package/dist/HttpApi/Operations/HttpOperation.d.ts.map +1 -0
- package/dist/HttpApi/Operations/HttpOperation.js +2 -0
- package/dist/HttpApi/Operations/HttpOperation.js.map +1 -0
- package/dist/HttpApi/Operations/Identity.d.ts +22 -0
- package/dist/HttpApi/Operations/Identity.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Identity.js +5 -0
- package/dist/HttpApi/Operations/Identity.js.map +1 -0
- package/dist/HttpApi/Operations/Jwt.d.ts +14 -0
- package/dist/HttpApi/Operations/Jwt.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Jwt.js +5 -0
- package/dist/HttpApi/Operations/Jwt.js.map +1 -0
- package/dist/HttpApi/Operations/LoginApproval.d.ts +16 -0
- package/dist/HttpApi/Operations/LoginApproval.d.ts.map +1 -0
- package/dist/HttpApi/Operations/LoginApproval.js +5 -0
- package/dist/HttpApi/Operations/LoginApproval.js.map +1 -0
- package/dist/HttpApi/Operations/MagicLink.d.ts +14 -0
- package/dist/HttpApi/Operations/MagicLink.d.ts.map +1 -0
- package/dist/HttpApi/Operations/MagicLink.js +5 -0
- package/dist/HttpApi/Operations/MagicLink.js.map +1 -0
- package/dist/HttpApi/Operations/Mfa.d.ts +24 -0
- package/dist/HttpApi/Operations/Mfa.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Mfa.js +5 -0
- package/dist/HttpApi/Operations/Mfa.js.map +1 -0
- package/dist/HttpApi/Operations/OAuth.d.ts +20 -0
- package/dist/HttpApi/Operations/OAuth.d.ts.map +1 -0
- package/dist/HttpApi/Operations/OAuth.js +5 -0
- package/dist/HttpApi/Operations/OAuth.js.map +1 -0
- package/dist/HttpApi/Operations/OAuthDeviceAuthorization.d.ts +23 -0
- package/dist/HttpApi/Operations/OAuthDeviceAuthorization.d.ts.map +1 -0
- package/dist/HttpApi/Operations/OAuthDeviceAuthorization.js +7 -0
- package/dist/HttpApi/Operations/OAuthDeviceAuthorization.js.map +1 -0
- package/dist/HttpApi/Operations/OAuthProviderAuthorization.d.ts +12 -0
- package/dist/HttpApi/Operations/OAuthProviderAuthorization.d.ts.map +1 -0
- package/dist/HttpApi/Operations/OAuthProviderAuthorization.js +5 -0
- package/dist/HttpApi/Operations/OAuthProviderAuthorization.js.map +1 -0
- package/dist/HttpApi/Operations/OAuthToken.d.ts +26 -0
- package/dist/HttpApi/Operations/OAuthToken.d.ts.map +1 -0
- package/dist/HttpApi/Operations/OAuthToken.js +9 -0
- package/dist/HttpApi/Operations/OAuthToken.js.map +1 -0
- package/dist/HttpApi/Operations/Passkey.d.ts +22 -0
- package/dist/HttpApi/Operations/Passkey.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Passkey.js +5 -0
- package/dist/HttpApi/Operations/Passkey.js.map +1 -0
- package/dist/HttpApi/Operations/Password.d.ts +22 -0
- package/dist/HttpApi/Operations/Password.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Password.js +5 -0
- package/dist/HttpApi/Operations/Password.js.map +1 -0
- package/dist/HttpApi/Operations/RecoveryCodes.d.ts +20 -0
- package/dist/HttpApi/Operations/RecoveryCodes.d.ts.map +1 -0
- package/dist/HttpApi/Operations/RecoveryCodes.js +5 -0
- package/dist/HttpApi/Operations/RecoveryCodes.js.map +1 -0
- package/dist/HttpApi/Operations/RefreshToken.d.ts +12 -0
- package/dist/HttpApi/Operations/RefreshToken.d.ts.map +1 -0
- package/dist/HttpApi/Operations/RefreshToken.js +5 -0
- package/dist/HttpApi/Operations/RefreshToken.js.map +1 -0
- package/dist/HttpApi/Operations/Security.d.ts +12 -0
- package/dist/HttpApi/Operations/Security.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Security.js +5 -0
- package/dist/HttpApi/Operations/Security.js.map +1 -0
- package/dist/HttpApi/Operations/SecurityTimeline.d.ts +19 -0
- package/dist/HttpApi/Operations/SecurityTimeline.d.ts.map +1 -0
- package/dist/HttpApi/Operations/SecurityTimeline.js +7 -0
- package/dist/HttpApi/Operations/SecurityTimeline.js.map +1 -0
- package/dist/HttpApi/Operations/Session.d.ts +22 -0
- package/dist/HttpApi/Operations/Session.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Session.js +5 -0
- package/dist/HttpApi/Operations/Session.js.map +1 -0
- package/dist/HttpApi/Operations/StepUp.d.ts +22 -0
- package/dist/HttpApi/Operations/StepUp.d.ts.map +1 -0
- package/dist/HttpApi/Operations/StepUp.js +5 -0
- package/dist/HttpApi/Operations/StepUp.js.map +1 -0
- package/dist/HttpApi/Operations/Totp.d.ts +20 -0
- package/dist/HttpApi/Operations/Totp.d.ts.map +1 -0
- package/dist/HttpApi/Operations/Totp.js +5 -0
- package/dist/HttpApi/Operations/Totp.js.map +1 -0
- package/dist/HttpApi/Operations/TrustedDevice.d.ts +23 -0
- package/dist/HttpApi/Operations/TrustedDevice.d.ts.map +1 -0
- package/dist/HttpApi/Operations/TrustedDevice.js +7 -0
- package/dist/HttpApi/Operations/TrustedDevice.js.map +1 -0
- package/dist/HttpApi/Operations/index.d.ts +28 -0
- package/dist/HttpApi/Operations/index.d.ts.map +1 -0
- package/dist/HttpApi/Operations/index.js +28 -0
- package/dist/HttpApi/Operations/index.js.map +1 -0
- package/dist/HttpApi/Passkey.d.ts +5 -0
- package/dist/HttpApi/Passkey.d.ts.map +1 -0
- package/dist/HttpApi/Passkey.js +5 -0
- package/dist/HttpApi/Passkey.js.map +1 -0
- package/dist/HttpApi/Password.d.ts +220 -0
- package/dist/HttpApi/Password.d.ts.map +1 -0
- package/dist/HttpApi/Password.js +237 -0
- package/dist/HttpApi/Password.js.map +1 -0
- package/dist/HttpApi/PasswordContract.d.ts +307 -0
- package/dist/HttpApi/PasswordContract.d.ts.map +1 -0
- package/dist/HttpApi/PasswordContract.js +63 -0
- package/dist/HttpApi/PasswordContract.js.map +1 -0
- package/dist/HttpApi/PasswordGuards.d.ts +82 -0
- package/dist/HttpApi/PasswordGuards.d.ts.map +1 -0
- package/dist/HttpApi/PasswordGuards.js +179 -0
- package/dist/HttpApi/PasswordGuards.js.map +1 -0
- package/dist/HttpApi/RecoveryCodes.d.ts +5 -0
- package/dist/HttpApi/RecoveryCodes.d.ts.map +1 -0
- package/dist/HttpApi/RecoveryCodes.js +5 -0
- package/dist/HttpApi/RecoveryCodes.js.map +1 -0
- package/dist/HttpApi/RefreshToken.d.ts +4 -0
- package/dist/HttpApi/RefreshToken.d.ts.map +1 -0
- package/dist/HttpApi/RefreshToken.js +4 -0
- package/dist/HttpApi/RefreshToken.js.map +1 -0
- package/dist/HttpApi/RequestGuards.d.ts +42 -0
- package/dist/HttpApi/RequestGuards.d.ts.map +1 -0
- package/dist/HttpApi/RequestGuards.js +194 -0
- package/dist/HttpApi/RequestGuards.js.map +1 -0
- package/dist/HttpApi/Schemas.d.ts +399 -84
- package/dist/HttpApi/Schemas.d.ts.map +1 -1
- package/dist/HttpApi/Schemas.js +225 -27
- package/dist/HttpApi/Schemas.js.map +1 -1
- package/dist/HttpApi/Security.d.ts +12 -93
- package/dist/HttpApi/Security.d.ts.map +1 -1
- package/dist/HttpApi/Security.js +65 -356
- package/dist/HttpApi/Security.js.map +1 -1
- package/dist/HttpApi/SecurityTimeline.d.ts +4 -0
- package/dist/HttpApi/SecurityTimeline.d.ts.map +1 -0
- package/dist/HttpApi/SecurityTimeline.js +4 -0
- package/dist/HttpApi/SecurityTimeline.js.map +1 -0
- package/dist/HttpApi/Session.d.ts +5 -0
- package/dist/HttpApi/Session.d.ts.map +1 -0
- package/dist/HttpApi/Session.js +5 -0
- package/dist/HttpApi/Session.js.map +1 -0
- package/dist/HttpApi/SessionGuards.d.ts +15 -0
- package/dist/HttpApi/SessionGuards.d.ts.map +1 -0
- package/dist/HttpApi/SessionGuards.js +37 -0
- package/dist/HttpApi/SessionGuards.js.map +1 -0
- package/dist/HttpApi/StepUp.d.ts +5 -0
- package/dist/HttpApi/StepUp.d.ts.map +1 -0
- package/dist/HttpApi/StepUp.js +5 -0
- package/dist/HttpApi/StepUp.js.map +1 -0
- package/dist/HttpApi/Totp.d.ts +5 -0
- package/dist/HttpApi/Totp.d.ts.map +1 -0
- package/dist/HttpApi/Totp.js +5 -0
- package/dist/HttpApi/Totp.js.map +1 -0
- package/dist/HttpApi/Transport.d.ts +4 -6
- package/dist/HttpApi/Transport.d.ts.map +1 -1
- package/dist/HttpApi/Transport.js +62 -36
- package/dist/HttpApi/Transport.js.map +1 -1
- package/dist/HttpApi/TrustedDevice.d.ts +4 -0
- package/dist/HttpApi/TrustedDevice.d.ts.map +1 -0
- package/dist/HttpApi/TrustedDevice.js +4 -0
- package/dist/HttpApi/TrustedDevice.js.map +1 -0
- package/dist/HttpApi/index.d.ts +11 -3
- package/dist/HttpApi/index.d.ts.map +1 -1
- package/dist/HttpApi/index.js +10 -2
- package/dist/HttpApi/index.js.map +1 -1
- package/dist/Identity.d.ts +138 -0
- package/dist/Identity.d.ts.map +1 -0
- package/dist/Identity.js +105 -0
- package/dist/Identity.js.map +1 -0
- package/dist/IdentityManagement.d.ts +189 -0
- package/dist/IdentityManagement.d.ts.map +1 -0
- package/dist/IdentityManagement.js +317 -0
- package/dist/IdentityManagement.js.map +1 -0
- package/dist/IncidentAction.d.ts +1 -4
- package/dist/IncidentAction.d.ts.map +1 -1
- package/dist/IncidentAction.js +15 -9
- package/dist/IncidentAction.js.map +1 -1
- package/dist/Internal.d.ts +2 -0
- package/dist/Internal.d.ts.map +1 -1
- package/dist/Internal.js +30 -0
- package/dist/Internal.js.map +1 -1
- package/dist/Invitation.d.ts +362 -0
- package/dist/Invitation.d.ts.map +1 -0
- package/dist/Invitation.js +633 -0
- package/dist/Invitation.js.map +1 -0
- package/dist/IpQualityScore.d.ts +38 -0
- package/dist/IpQualityScore.d.ts.map +1 -0
- package/dist/IpQualityScore.js +215 -0
- package/dist/IpQualityScore.js.map +1 -0
- package/dist/Jwt.d.ts +8 -29
- package/dist/Jwt.d.ts.map +1 -1
- package/dist/Jwt.js +67 -56
- package/dist/Jwt.js.map +1 -1
- package/dist/LoginApproval.d.ts +15 -30
- package/dist/LoginApproval.d.ts.map +1 -1
- package/dist/LoginApproval.js +47 -41
- package/dist/LoginApproval.js.map +1 -1
- package/dist/LoginNotification.d.ts +7 -11
- package/dist/LoginNotification.d.ts.map +1 -1
- package/dist/LoginNotification.js +30 -17
- package/dist/LoginNotification.js.map +1 -1
- package/dist/LoginRisk.d.ts +11 -13
- package/dist/LoginRisk.d.ts.map +1 -1
- package/dist/LoginRisk.js +66 -26
- package/dist/LoginRisk.js.map +1 -1
- package/dist/LoginRiskEnrichment.d.ts +145 -0
- package/dist/LoginRiskEnrichment.d.ts.map +1 -0
- package/dist/LoginRiskEnrichment.js +220 -0
- package/dist/LoginRiskEnrichment.js.map +1 -0
- package/dist/MagicLink.d.ts +9 -8
- package/dist/MagicLink.d.ts.map +1 -1
- package/dist/MagicLink.js +40 -73
- package/dist/MagicLink.js.map +1 -1
- package/dist/Mailer.d.ts +19 -12
- package/dist/Mailer.d.ts.map +1 -1
- package/dist/Mailer.js +10 -12
- package/dist/Mailer.js.map +1 -1
- package/dist/OAuth.d.ts +138 -96
- package/dist/OAuth.d.ts.map +1 -1
- package/dist/OAuth.js +522 -221
- package/dist/OAuth.js.map +1 -1
- package/dist/OAuthDeviceAuthorization.d.ts +378 -0
- package/dist/OAuthDeviceAuthorization.d.ts.map +1 -0
- package/dist/OAuthDeviceAuthorization.js +860 -0
- package/dist/OAuthDeviceAuthorization.js.map +1 -0
- package/dist/OAuthDeviceClient.d.ts +76 -0
- package/dist/OAuthDeviceClient.d.ts.map +1 -0
- package/dist/OAuthDeviceClient.js +362 -0
- package/dist/OAuthDeviceClient.js.map +1 -0
- package/dist/Passkey.d.ts +15 -17
- package/dist/Passkey.d.ts.map +1 -1
- package/dist/Passkey.js +86 -39
- package/dist/Passkey.js.map +1 -1
- package/dist/PasskeyBrowser.d.ts +39 -0
- package/dist/PasskeyBrowser.d.ts.map +1 -0
- package/dist/PasskeyBrowser.js +206 -0
- package/dist/PasskeyBrowser.js.map +1 -0
- package/dist/PasskeySimpleWebAuthn.d.ts.map +1 -1
- package/dist/PasskeySimpleWebAuthn.js +19 -7
- package/dist/PasskeySimpleWebAuthn.js.map +1 -1
- package/dist/Password.d.ts +71 -37
- package/dist/Password.d.ts.map +1 -1
- package/dist/Password.js +295 -81
- package/dist/Password.js.map +1 -1
- package/dist/PasswordRisk.d.ts +63 -0
- package/dist/PasswordRisk.d.ts.map +1 -0
- package/dist/PasswordRisk.js +37 -0
- package/dist/PasswordRisk.js.map +1 -0
- package/dist/Permission.d.ts +308 -0
- package/dist/Permission.d.ts.map +1 -0
- package/dist/Permission.js +827 -0
- package/dist/Permission.js.map +1 -0
- package/dist/Policy.d.ts +31 -18
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js +58 -14
- package/dist/Policy.js.map +1 -1
- package/dist/PostgresDelegatedAccessStorageMigrations.d.ts +7 -0
- package/dist/PostgresDelegatedAccessStorageMigrations.d.ts.map +1 -0
- package/dist/PostgresDelegatedAccessStorageMigrations.js +119 -0
- package/dist/PostgresDelegatedAccessStorageMigrations.js.map +1 -0
- package/dist/PostgresStorageMigrations.d.ts +16 -0
- package/dist/PostgresStorageMigrations.d.ts.map +1 -0
- package/dist/PostgresStorageMigrations.js +674 -0
- package/dist/PostgresStorageMigrations.js.map +1 -0
- package/dist/Privacy.d.ts +0 -3
- package/dist/Privacy.d.ts.map +1 -1
- package/dist/Privacy.js +2 -5
- package/dist/Privacy.js.map +1 -1
- package/dist/RateLimiter.d.ts +0 -3
- package/dist/RateLimiter.d.ts.map +1 -1
- package/dist/RateLimiter.js +1 -4
- package/dist/RateLimiter.js.map +1 -1
- package/dist/RecoveryCode.d.ts +83 -11
- package/dist/RecoveryCode.d.ts.map +1 -1
- package/dist/RecoveryCode.js +273 -75
- package/dist/RecoveryCode.js.map +1 -1
- package/dist/RecoveryPolicy.d.ts +81 -0
- package/dist/RecoveryPolicy.d.ts.map +1 -0
- package/dist/RecoveryPolicy.js +119 -0
- package/dist/RecoveryPolicy.js.map +1 -0
- package/dist/RefreshToken.d.ts +0 -9
- package/dist/RefreshToken.d.ts.map +1 -1
- package/dist/RefreshToken.js +31 -22
- package/dist/RefreshToken.js.map +1 -1
- package/dist/Retention.d.ts +6 -1
- package/dist/Retention.d.ts.map +1 -1
- package/dist/Retention.js +49 -12
- package/dist/Retention.js.map +1 -1
- package/dist/SecurityTimeline.d.ts +1 -4
- package/dist/SecurityTimeline.d.ts.map +1 -1
- package/dist/SecurityTimeline.js +110 -17
- package/dist/SecurityTimeline.js.map +1 -1
- package/dist/Sessions.d.ts +124 -29
- package/dist/Sessions.d.ts.map +1 -1
- package/dist/Sessions.js +626 -94
- package/dist/Sessions.js.map +1 -1
- package/dist/SqliteStorageSchemaData.d.ts +2 -0
- package/dist/SqliteStorageSchemaData.d.ts.map +1 -0
- package/dist/SqliteStorageSchemaData.js +508 -0
- package/dist/SqliteStorageSchemaData.js.map +1 -0
- package/dist/StepUp.d.ts +132 -11
- package/dist/StepUp.d.ts.map +1 -1
- package/dist/StepUp.js +387 -19
- package/dist/StepUp.js.map +1 -1
- package/dist/Storage.d.ts +89 -23
- package/dist/Storage.d.ts.map +1 -1
- package/dist/Storage.js +10 -12
- package/dist/Storage.js.map +1 -1
- package/dist/StorageMigrations.d.ts +7 -1
- package/dist/StorageMigrations.d.ts.map +1 -1
- package/dist/StorageMigrations.js +256 -0
- package/dist/StorageMigrations.js.map +1 -1
- package/dist/StorageSchemaGenerator.d.ts +544 -0
- package/dist/StorageSchemaGenerator.d.ts.map +1 -0
- package/dist/StorageSchemaGenerator.js +1418 -0
- package/dist/StorageSchemaGenerator.js.map +1 -0
- package/dist/StrongFactor.d.ts +64 -0
- package/dist/StrongFactor.d.ts.map +1 -0
- package/dist/StrongFactor.js +100 -0
- package/dist/StrongFactor.js.map +1 -0
- package/dist/Testing.js +2 -2
- package/dist/Testing.js.map +1 -1
- package/dist/Totp.d.ts +88 -13
- package/dist/Totp.d.ts.map +1 -1
- package/dist/Totp.js +192 -34
- package/dist/Totp.js.map +1 -1
- package/dist/TrustedDevice.d.ts +0 -9
- package/dist/TrustedDevice.d.ts.map +1 -1
- package/dist/TrustedDevice.js +15 -17
- package/dist/TrustedDevice.js.map +1 -1
- package/dist/WaitUntil.d.ts +0 -3
- package/dist/WaitUntil.d.ts.map +1 -1
- package/dist/WaitUntil.js +1 -4
- package/dist/WaitUntil.js.map +1 -1
- package/dist/Webhook.d.ts +42 -12
- package/dist/Webhook.d.ts.map +1 -1
- package/dist/Webhook.js +165 -26
- package/dist/Webhook.js.map +1 -1
- package/dist/alchemy/cloudflare/Email.d.ts.map +1 -1
- package/dist/alchemy/cloudflare/Email.js +9 -4
- package/dist/alchemy/cloudflare/Email.js.map +1 -1
- package/dist/cloudflare/Email.js +1 -1
- package/dist/cloudflare/Email.js.map +1 -1
- package/dist/cloudflare/RequestMetadata.d.ts +49 -0
- package/dist/cloudflare/RequestMetadata.d.ts.map +1 -0
- package/dist/cloudflare/RequestMetadata.js +71 -0
- package/dist/cloudflare/RequestMetadata.js.map +1 -0
- package/dist/index.d.ts +0 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -35
- package/dist/index.js.map +1 -1
- package/dist/internal/AuthFlowFinalizer.d.ts +31 -0
- package/dist/internal/AuthFlowFinalizer.d.ts.map +1 -0
- package/dist/internal/AuthFlowFinalizer.js +182 -0
- package/dist/internal/AuthFlowFinalizer.js.map +1 -0
- package/migrations/0001_auth_storage.sql +1 -0
- package/migrations/0006_auth_totp_factor.sql +1 -0
- package/migrations/0024_auth_permission.sql +39 -0
- package/migrations/0025_auth_permission_definition.sql +19 -0
- package/migrations/0026_auth_user_identity.sql +59 -0
- package/migrations/0027_auth_audit_log_storage_order.sql +46 -0
- package/migrations/0028_auth_oauth_client_secret_key.sql +39 -0
- package/migrations/0029_auth_oauth_device_authorization.sql +28 -0
- package/migrations/delegated-access/0001_auth_delegated_access.sql +152 -0
- package/migrations/postgres/0001_auth_core.sql +77 -0
- package/migrations/postgres/0002_auth_security_oauth.sql +65 -0
- package/migrations/postgres/0003_auth_credentials_tokens.sql +43 -0
- package/migrations/postgres/0004_auth_security_history.sql +103 -0
- package/migrations/postgres/0005_auth_webhooks.sql +29 -0
- package/migrations/postgres/0006_auth_domain_timeline.sql +50 -0
- package/migrations/postgres/0007_auth_oauth_clients.sql +85 -0
- package/migrations/postgres/0008_auth_oauth_tokens.sql +63 -0
- package/migrations/postgres/0009_auth_permissions.sql +66 -0
- package/migrations/postgres/0010_auth_oauth_device_authorization.sql +50 -0
- package/migrations/postgres/delegated-access/0001_auth_delegated_access.sql +112 -0
- package/package.json +309 -2
package/dist/Sessions.js
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
import { Context, Data, Duration, Effect, Layer, Option } from "effect";
|
|
1
|
+
import { Context, Data, Duration, Effect, Layer, Option, Result } from "effect";
|
|
2
|
+
import { AuthenticationEvidenceTimeError, CustomEvidencePolicies, CustomEvidencePolicyError, compactAuthenticationEventsResult, deriveAssuranceResult, deriveMfaVerifiedAtResult, emptyCustomEvidencePolicyRegistry, maximumSessionAuthenticationEvents, validateAuthenticationEvidenceTimestamps, } from "./Assurance.js";
|
|
2
3
|
import { AuthSecrets, AuthSessionCookieConfig, AuthSessionsConfig, } from "./AuthConfig.js";
|
|
3
4
|
import { Crypto } from "./Crypto.js";
|
|
4
|
-
import { SessionId, SessionToken, UnixMillis } from "./Identifiers.js";
|
|
5
|
+
import { SessionId, SessionToken, UnixMillis, } from "./Identifiers.js";
|
|
5
6
|
import { addMillis, currentUnixMillis, timingSafeEqualString, } from "./Internal.js";
|
|
7
|
+
import { RecoveryCodeSessionRotateStore } from "./RecoveryCode.js";
|
|
6
8
|
import { SessionStore } from "./Storage.js";
|
|
9
|
+
import { TotpSessionRotateStore } from "./Totp.js";
|
|
7
10
|
export const sessionRequestMetadataKey = "__effectAuthRequest";
|
|
8
11
|
export const defaultSessionTtlPolicy = {
|
|
9
12
|
idleTtl: Duration.days(30),
|
|
10
13
|
absoluteTtl: Duration.days(90),
|
|
11
14
|
refreshAfter: Duration.days(1),
|
|
12
15
|
};
|
|
16
|
+
export class RecoveryCodeSessionRotation extends Context.Service()("auth/RecoveryCodeSessionRotation") {
|
|
17
|
+
}
|
|
18
|
+
export class TotpSessionRotation extends Context.Service()("auth/TotpSessionRotation") {
|
|
19
|
+
}
|
|
13
20
|
export class SessionCreateError extends Data.TaggedError("SessionCreateError") {
|
|
14
21
|
}
|
|
15
22
|
export class SessionValidateError extends Data.TaggedError("SessionValidateError") {
|
|
@@ -26,9 +33,6 @@ export class SessionRevokeError extends Data.TaggedError("SessionRevokeError") {
|
|
|
26
33
|
}
|
|
27
34
|
export class Sessions extends Context.Service()("auth/Sessions") {
|
|
28
35
|
}
|
|
29
|
-
(function (Sessions) {
|
|
30
|
-
Sessions.make = (service) => Sessions.of(service);
|
|
31
|
-
})(Sessions || (Sessions = {}));
|
|
32
36
|
const resolveTtl = (ttl) => ttl ?? defaultSessionTtlPolicy;
|
|
33
37
|
const ttlMillis = (ttl) => Duration.toMillis(ttl);
|
|
34
38
|
const sessionExpiresAt = (now, authTime, ttl) => UnixMillis(Math.min(Number(addMillis(now, ttlMillis(ttl.idleTtl))), Number(addMillis(authTime, ttlMillis(ttl.absoluteTtl)))));
|
|
@@ -59,9 +63,123 @@ const issuedFromRow = (row, token) => ({
|
|
|
59
63
|
expiresAt: row.expiresAt,
|
|
60
64
|
aal: row.aal,
|
|
61
65
|
amr: row.amr,
|
|
62
|
-
|
|
66
|
+
authenticationEvents: row.authenticationEvents,
|
|
67
|
+
...(row.mfaVerifiedAt === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: { mfaVerifiedAt: row.mfaVerifiedAt }),
|
|
63
70
|
claims: row.claims,
|
|
71
|
+
...(row.rotatedAt === undefined ? {} : { rotatedAt: row.rotatedAt }),
|
|
72
|
+
});
|
|
73
|
+
const requirements = (claims) => {
|
|
74
|
+
const sorted = [];
|
|
75
|
+
for (const requirement of new Set(claims?.requirements)) {
|
|
76
|
+
const index = sorted.findIndex((item) => item.localeCompare(requirement) > 0);
|
|
77
|
+
if (index === -1) {
|
|
78
|
+
sorted.push(requirement);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
sorted.splice(index, 0, requirement);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return sorted;
|
|
85
|
+
};
|
|
86
|
+
const changedRequirements = (left, right) => left.filter((requirement) => !right.includes(requirement));
|
|
87
|
+
/** Decorates only committed assurance rotations; audit failures never fail authentication. */
|
|
88
|
+
export const makeSessionsAssuranceAudit = (dependencies) => ({
|
|
89
|
+
...dependencies.sessions,
|
|
90
|
+
assureAndRotate: (input) => dependencies.sessions.validate(input.token).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
91
|
+
message: "Failed to load session before assurance rotation",
|
|
92
|
+
cause: cause.cause instanceof CustomEvidencePolicyError ||
|
|
93
|
+
cause.cause instanceof AuthenticationEvidenceTimeError
|
|
94
|
+
? cause.cause
|
|
95
|
+
: cause,
|
|
96
|
+
})), Effect.flatMap((before) => dependencies.sessions.assureAndRotate(input).pipe(Effect.tap((result) => {
|
|
97
|
+
const transition = dependencies.options.transition(input, result);
|
|
98
|
+
const rotatedAt = result.rotatedAt ?? result.authTime;
|
|
99
|
+
const context = dependencies.options.context(result.userId, result.sessionId);
|
|
100
|
+
const oldRequirements = requirements(before.currentSession.claims);
|
|
101
|
+
const newRequirements = requirements(result.claims);
|
|
102
|
+
return dependencies.auditLog
|
|
103
|
+
.emit({
|
|
104
|
+
type: transition.type,
|
|
105
|
+
actor: context.actor,
|
|
106
|
+
userId: result.userId,
|
|
107
|
+
sessionId: result.sessionId,
|
|
108
|
+
oldAal: before.currentSession.aal,
|
|
109
|
+
newAal: result.aal,
|
|
110
|
+
amr: result.amr,
|
|
111
|
+
method: transition.method,
|
|
112
|
+
rotatedAt,
|
|
113
|
+
requirementsEntered: changedRequirements(newRequirements, oldRequirements),
|
|
114
|
+
requirementsCleared: changedRequirements(oldRequirements, newRequirements),
|
|
115
|
+
occurredAt: rotatedAt,
|
|
116
|
+
...(context.request === undefined
|
|
117
|
+
? {}
|
|
118
|
+
: { request: context.request }),
|
|
119
|
+
...(dependencies.options.eventId === undefined
|
|
120
|
+
? {}
|
|
121
|
+
: {
|
|
122
|
+
id: dependencies.options.eventId(transition.type, result.sessionId, rotatedAt),
|
|
123
|
+
}),
|
|
124
|
+
})
|
|
125
|
+
.pipe(Effect.ignore);
|
|
126
|
+
})))),
|
|
64
127
|
});
|
|
128
|
+
const emitAtomicAssurance = (auditLog, options, type, method, before, result) => {
|
|
129
|
+
const rotatedAt = result.rotatedAt ?? result.authTime;
|
|
130
|
+
const context = options.context(result.userId, result.sessionId);
|
|
131
|
+
const newRequirements = requirements(result.claims);
|
|
132
|
+
const requirementsEntered = type === "auth.session.recovery_remediation.entered" &&
|
|
133
|
+
newRequirements.includes("recovery_remediation")
|
|
134
|
+
? ["recovery_remediation"]
|
|
135
|
+
: [];
|
|
136
|
+
return auditLog
|
|
137
|
+
.emit({
|
|
138
|
+
type,
|
|
139
|
+
actor: context.actor,
|
|
140
|
+
userId: result.userId,
|
|
141
|
+
sessionId: result.sessionId,
|
|
142
|
+
oldAal: before.level,
|
|
143
|
+
newAal: result.aal,
|
|
144
|
+
amr: result.amr,
|
|
145
|
+
method,
|
|
146
|
+
rotatedAt,
|
|
147
|
+
requirementsEntered,
|
|
148
|
+
requirementsCleared: [],
|
|
149
|
+
occurredAt: rotatedAt,
|
|
150
|
+
...(context.request === undefined ? {} : { request: context.request }),
|
|
151
|
+
...(options.eventId === undefined
|
|
152
|
+
? {}
|
|
153
|
+
: { id: options.eventId(type, result.sessionId, rotatedAt) }),
|
|
154
|
+
})
|
|
155
|
+
.pipe(Effect.ignore);
|
|
156
|
+
};
|
|
157
|
+
export const makeTotpSessionRotationAudit = (dependencies) => {
|
|
158
|
+
const customEvidencePolicies = dependencies.customEvidencePolicies ?? emptyCustomEvidencePolicyRegistry;
|
|
159
|
+
return TotpSessionRotation.of({
|
|
160
|
+
acceptAndRotate: (input) => Effect.fromResult(deriveAssuranceResult(input.expectedAuthenticationEvents, {
|
|
161
|
+
customEvidencePolicies,
|
|
162
|
+
})).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
163
|
+
message: "Session evidence policy validation failed",
|
|
164
|
+
cause,
|
|
165
|
+
})), Effect.flatMap((before) => dependencies.rotation
|
|
166
|
+
.acceptAndRotate(input)
|
|
167
|
+
.pipe(Effect.tap((result) => emitAtomicAssurance(dependencies.auditLog, dependencies.options, "auth.session.step_up_completed", "totp", before, result))))),
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
export const makeRecoveryCodeSessionRotationAudit = (dependencies) => {
|
|
171
|
+
const customEvidencePolicies = dependencies.customEvidencePolicies ?? emptyCustomEvidencePolicyRegistry;
|
|
172
|
+
return RecoveryCodeSessionRotation.of({
|
|
173
|
+
consumeAndRotate: (input) => Effect.fromResult(deriveAssuranceResult(input.expectedAuthenticationEvents, {
|
|
174
|
+
customEvidencePolicies,
|
|
175
|
+
})).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
176
|
+
message: "Session evidence policy validation failed",
|
|
177
|
+
cause,
|
|
178
|
+
})), Effect.flatMap((before) => dependencies.rotation
|
|
179
|
+
.consumeAndRotate(input)
|
|
180
|
+
.pipe(Effect.tap((result) => emitAtomicAssurance(dependencies.auditLog, dependencies.options, "auth.session.recovery_remediation.entered", "recovery_code", before, result))))),
|
|
181
|
+
});
|
|
182
|
+
};
|
|
65
183
|
const currentFromRow = (row) => ({
|
|
66
184
|
sessionId: row.id,
|
|
67
185
|
userId: row.userId,
|
|
@@ -69,7 +187,10 @@ const currentFromRow = (row) => ({
|
|
|
69
187
|
expiresAt: row.expiresAt,
|
|
70
188
|
aal: row.aal,
|
|
71
189
|
amr: row.amr,
|
|
72
|
-
|
|
190
|
+
authenticationEvents: row.authenticationEvents,
|
|
191
|
+
...(row.mfaVerifiedAt === undefined
|
|
192
|
+
? {}
|
|
193
|
+
: { mfaVerifiedAt: row.mfaVerifiedAt }),
|
|
73
194
|
claims: row.claims,
|
|
74
195
|
});
|
|
75
196
|
const infoFromRow = (row) => ({
|
|
@@ -81,25 +202,44 @@ const infoFromRow = (row) => ({
|
|
|
81
202
|
expiresAt: row.expiresAt,
|
|
82
203
|
aal: row.aal,
|
|
83
204
|
amr: row.amr,
|
|
84
|
-
|
|
205
|
+
authenticationEvents: row.authenticationEvents,
|
|
206
|
+
...(row.mfaVerifiedAt === undefined
|
|
207
|
+
? {}
|
|
208
|
+
: { mfaVerifiedAt: row.mfaVerifiedAt }),
|
|
85
209
|
claims: row.claims,
|
|
86
210
|
...(row.metadata === undefined ? {} : { metadata: row.metadata }),
|
|
87
211
|
});
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
212
|
+
const asEvidence = (evidence) => Array.isArray(evidence) ? evidence : [evidence];
|
|
213
|
+
const summarizeAuthenticationEventsResult = (events, customEvidencePolicies) => {
|
|
214
|
+
const assurance = deriveAssuranceResult(events, { customEvidencePolicies });
|
|
215
|
+
if (Result.isFailure(assurance)) {
|
|
216
|
+
return Result.fail(assurance.failure);
|
|
217
|
+
}
|
|
218
|
+
const mfaVerifiedAt = deriveMfaVerifiedAtResult(events, customEvidencePolicies);
|
|
219
|
+
if (Result.isFailure(mfaVerifiedAt)) {
|
|
220
|
+
return Result.fail(mfaVerifiedAt.failure);
|
|
221
|
+
}
|
|
222
|
+
return Result.succeed({
|
|
223
|
+
assurance: assurance.success,
|
|
224
|
+
mfaVerifiedAt: mfaVerifiedAt.success,
|
|
225
|
+
});
|
|
92
226
|
};
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
227
|
+
const prepareSessionAssuranceResult = (events, customEvidencePolicies, serverNow) => {
|
|
228
|
+
const timestampValidation = validateAuthenticationEvidenceTimestamps(events, serverNow);
|
|
229
|
+
if (Result.isFailure(timestampValidation)) {
|
|
230
|
+
return Result.fail(timestampValidation.failure);
|
|
231
|
+
}
|
|
232
|
+
const authenticationEvents = compactAuthenticationEventsResult(events, maximumSessionAuthenticationEvents, customEvidencePolicies);
|
|
233
|
+
if (Result.isFailure(authenticationEvents)) {
|
|
234
|
+
return Result.fail(authenticationEvents.failure);
|
|
101
235
|
}
|
|
102
|
-
|
|
236
|
+
const summary = summarizeAuthenticationEventsResult(authenticationEvents.success, customEvidencePolicies);
|
|
237
|
+
return Result.isFailure(summary)
|
|
238
|
+
? Result.fail(summary.failure)
|
|
239
|
+
: Result.succeed({
|
|
240
|
+
authenticationEvents: authenticationEvents.success,
|
|
241
|
+
...summary.success,
|
|
242
|
+
});
|
|
103
243
|
};
|
|
104
244
|
const sessionActivityTime = (row) => Number(row.lastSeenAt ?? row.createdAt);
|
|
105
245
|
const activeSessionsForUser = (rows, now, ttl) => {
|
|
@@ -130,62 +270,116 @@ export const makeSessions = (dependencies) => {
|
|
|
130
270
|
const ttl = resolveTtl(dependencies.ttl);
|
|
131
271
|
const sessionIdBytes = dependencies.sessionIdBytes ?? 16;
|
|
132
272
|
const sessionSecretBytes = dependencies.sessionSecretBytes ?? 32;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
273
|
+
const customEvidencePolicies = dependencies.customEvidencePolicies ?? emptyCustomEvidencePolicyRegistry;
|
|
274
|
+
const prepareAssurance = (events, serverNow) => prepareSessionAssuranceResult(events, customEvidencePolicies, serverNow);
|
|
275
|
+
const summarize = (events) => summarizeAuthenticationEventsResult(events, customEvidencePolicies);
|
|
276
|
+
const validateRowAssurance = (row, serverNow) => {
|
|
277
|
+
const timestampValidation = validateAuthenticationEvidenceTimestamps(row.authenticationEvents, serverNow);
|
|
278
|
+
if (Result.isFailure(timestampValidation)) {
|
|
279
|
+
return Result.fail(timestampValidation.failure);
|
|
280
|
+
}
|
|
281
|
+
const summary = summarize(row.authenticationEvents);
|
|
282
|
+
if (Result.isFailure(summary)) {
|
|
283
|
+
return Result.fail(summary.failure);
|
|
284
|
+
}
|
|
285
|
+
const { assurance, mfaVerifiedAt } = summary.success;
|
|
286
|
+
if (assurance.authenticatedAt === undefined ||
|
|
287
|
+
!assurance.primaryEstablished ||
|
|
288
|
+
assurance.level !== row.aal ||
|
|
289
|
+
JSON.stringify(assurance.amr) !== JSON.stringify(row.amr) ||
|
|
290
|
+
Number(assurance.authenticatedAt) !== Number(row.authTime) ||
|
|
291
|
+
mfaVerifiedAt !== row.mfaVerifiedAt) {
|
|
292
|
+
return Result.fail(new Error("Session assurance summary does not match registered evidence policy"));
|
|
293
|
+
}
|
|
294
|
+
return Result.void;
|
|
295
|
+
};
|
|
296
|
+
const prepareCreate = Effect.fn("auth.session.prepare_create")(function* (input) {
|
|
297
|
+
const serverNow = yield* currentUnixMillis;
|
|
298
|
+
const now = input.now ?? serverNow;
|
|
299
|
+
const preparedAssurance = yield* Effect.fromResult(prepareAssurance(input.authenticationEvents, serverNow)).pipe(Effect.mapError((cause) => new SessionCreateError({
|
|
300
|
+
message: "Session evidence policy validation failed",
|
|
301
|
+
cause,
|
|
302
|
+
})));
|
|
303
|
+
const { assurance, authenticationEvents, mfaVerifiedAt: derivedMfaVerifiedAt, } = preparedAssurance;
|
|
304
|
+
if (authenticationEvents.length === 0) {
|
|
305
|
+
return yield* new SessionCreateError({
|
|
306
|
+
message: "At least one authentication event is required",
|
|
139
307
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
message: "
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
message: "
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
308
|
+
}
|
|
309
|
+
if (!assurance.primaryEstablished) {
|
|
310
|
+
return yield* new SessionCreateError({
|
|
311
|
+
message: "Authentication events did not establish a primary factor",
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
const authTime = assurance.authenticatedAt;
|
|
315
|
+
if (authTime === undefined) {
|
|
316
|
+
return yield* new SessionCreateError({
|
|
317
|
+
message: "Authentication events did not establish an auth time",
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
yield* Effect.annotateCurrentSpan({
|
|
321
|
+
"auth.aal": assurance.level,
|
|
322
|
+
"auth.amr_count": assurance.amr.length,
|
|
323
|
+
});
|
|
324
|
+
const inputTtl = resolveTtl(input.ttl ?? ttl);
|
|
325
|
+
const sessionId = SessionId(yield* dependencies.crypto.randomToken(sessionIdBytes).pipe(Effect.mapError((cause) => new SessionCreateError({
|
|
326
|
+
message: "Failed to generate session id",
|
|
327
|
+
cause,
|
|
328
|
+
}))));
|
|
329
|
+
const secret = yield* dependencies.crypto
|
|
330
|
+
.randomToken(sessionSecretBytes)
|
|
331
|
+
.pipe(Effect.mapError((cause) => new SessionCreateError({
|
|
332
|
+
message: "Failed to generate session secret",
|
|
333
|
+
cause,
|
|
334
|
+
})));
|
|
335
|
+
const token = makeSessionToken(sessionId, secret);
|
|
336
|
+
const secretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, secret).pipe(Effect.mapError((cause) => new SessionCreateError({
|
|
337
|
+
message: "Failed to hash session secret",
|
|
338
|
+
cause,
|
|
339
|
+
})));
|
|
340
|
+
const expiresAt = sessionExpiresAt(now, authTime, inputTtl);
|
|
341
|
+
const row = {
|
|
342
|
+
id: sessionId,
|
|
343
|
+
userId: input.userId,
|
|
344
|
+
secretHash,
|
|
345
|
+
createdAt: now,
|
|
346
|
+
expiresAt,
|
|
347
|
+
authTime,
|
|
348
|
+
authenticationEvents,
|
|
349
|
+
aal: assurance.level,
|
|
350
|
+
amr: assurance.amr,
|
|
351
|
+
mfaVerifiedAt: derivedMfaVerifiedAt,
|
|
352
|
+
claims: input.claims,
|
|
353
|
+
metadata: input.metadata,
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
row,
|
|
357
|
+
session: {
|
|
177
358
|
sessionId,
|
|
178
359
|
userId: input.userId,
|
|
179
360
|
token,
|
|
180
|
-
authTime
|
|
361
|
+
authTime,
|
|
181
362
|
expiresAt,
|
|
182
|
-
aal:
|
|
183
|
-
amr:
|
|
184
|
-
|
|
363
|
+
aal: assurance.level,
|
|
364
|
+
amr: assurance.amr,
|
|
365
|
+
authenticationEvents,
|
|
366
|
+
...(derivedMfaVerifiedAt === undefined
|
|
185
367
|
? {}
|
|
186
|
-
: { mfaVerifiedAt:
|
|
368
|
+
: { mfaVerifiedAt: derivedMfaVerifiedAt }),
|
|
187
369
|
claims: input.claims,
|
|
188
|
-
}
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
});
|
|
373
|
+
return Sessions.of({
|
|
374
|
+
customEvidencePolicies,
|
|
375
|
+
prepareCreate,
|
|
376
|
+
create: Effect.fn("auth.session.create")(function* (input) {
|
|
377
|
+
const prepared = yield* prepareCreate(input);
|
|
378
|
+
yield* dependencies.sessionStore.insert(prepared.row).pipe(Effect.mapError((cause) => new SessionCreateError({
|
|
379
|
+
message: "Failed to store session",
|
|
380
|
+
cause,
|
|
381
|
+
})));
|
|
382
|
+
return prepared.session;
|
|
189
383
|
}),
|
|
190
384
|
validate: Effect.fn("auth.session.validate")(function* (token) {
|
|
191
385
|
const parsed = parseSessionToken(token);
|
|
@@ -209,6 +403,10 @@ export const makeSessions = (dependencies) => {
|
|
|
209
403
|
});
|
|
210
404
|
}
|
|
211
405
|
const row = rowOption.value;
|
|
406
|
+
yield* Effect.fromResult(validateRowAssurance(row, now)).pipe(Effect.mapError((cause) => new SessionValidateError({
|
|
407
|
+
message: "Session evidence policy validation failed",
|
|
408
|
+
cause,
|
|
409
|
+
})));
|
|
212
410
|
if (isExpired(row, now, ttl)) {
|
|
213
411
|
return yield* new SessionValidateError({ message: "Session expired" });
|
|
214
412
|
}
|
|
@@ -247,6 +445,10 @@ export const makeSessions = (dependencies) => {
|
|
|
247
445
|
return yield* new SessionRefreshError({ message: "Session not found" });
|
|
248
446
|
}
|
|
249
447
|
const row = rowOption.value;
|
|
448
|
+
yield* Effect.fromResult(validateRowAssurance(row, now)).pipe(Effect.mapError((cause) => new SessionRefreshError({
|
|
449
|
+
message: "Session evidence policy validation failed",
|
|
450
|
+
cause,
|
|
451
|
+
})));
|
|
250
452
|
if (isExpired(row, now, ttl)) {
|
|
251
453
|
return yield* new SessionRefreshError({ message: "Session expired" });
|
|
252
454
|
}
|
|
@@ -285,6 +487,19 @@ export const makeSessions = (dependencies) => {
|
|
|
285
487
|
}),
|
|
286
488
|
rotate: Effect.fn("auth.session.rotate")(function* (input) {
|
|
287
489
|
const now = yield* currentUnixMillis;
|
|
490
|
+
const rowOption = yield* dependencies.sessionStore
|
|
491
|
+
.findById(input.sessionId)
|
|
492
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
493
|
+
message: "Failed to load session",
|
|
494
|
+
cause,
|
|
495
|
+
})));
|
|
496
|
+
if (Option.isNone(rowOption)) {
|
|
497
|
+
return yield* new SessionRotateError({ message: "Session not found" });
|
|
498
|
+
}
|
|
499
|
+
yield* Effect.fromResult(validateRowAssurance(rowOption.value, now)).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
500
|
+
message: "Session evidence policy validation failed",
|
|
501
|
+
cause,
|
|
502
|
+
})));
|
|
288
503
|
const secret = yield* dependencies.crypto
|
|
289
504
|
.randomToken(sessionSecretBytes)
|
|
290
505
|
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
@@ -324,6 +539,10 @@ export const makeSessions = (dependencies) => {
|
|
|
324
539
|
message: "Session not found",
|
|
325
540
|
});
|
|
326
541
|
}
|
|
542
|
+
yield* Effect.fromResult(validateRowAssurance(rowOption.value, now)).pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
543
|
+
message: "Session evidence policy validation failed",
|
|
544
|
+
cause,
|
|
545
|
+
})));
|
|
327
546
|
if (isExpired(rowOption.value, now, ttl)) {
|
|
328
547
|
return yield* new SessionUpdateClaimsError({
|
|
329
548
|
message: "Session expired",
|
|
@@ -333,11 +552,6 @@ export const makeSessions = (dependencies) => {
|
|
|
333
552
|
.updateClaims({
|
|
334
553
|
sessionId: input.sessionId,
|
|
335
554
|
...(input.claims === undefined ? {} : { claims: input.claims }),
|
|
336
|
-
...(input.aal === undefined ? {} : { aal: input.aal }),
|
|
337
|
-
...(input.amr === undefined ? {} : { amr: input.amr }),
|
|
338
|
-
...(input.mfaVerifiedAt === undefined
|
|
339
|
-
? {}
|
|
340
|
-
: { mfaVerifiedAt: input.mfaVerifiedAt }),
|
|
341
555
|
})
|
|
342
556
|
.pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
343
557
|
message: "Failed to update session claims",
|
|
@@ -350,12 +564,154 @@ export const makeSessions = (dependencies) => {
|
|
|
350
564
|
}
|
|
351
565
|
return currentFromRow(updated.value);
|
|
352
566
|
}),
|
|
567
|
+
appendEvidence: Effect.fn("auth.session.append_evidence")(function* (sessionId, evidence, claims) {
|
|
568
|
+
const now = yield* currentUnixMillis;
|
|
569
|
+
const rowOption = yield* dependencies.sessionStore
|
|
570
|
+
.findById(sessionId)
|
|
571
|
+
.pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
572
|
+
message: "Failed to load session",
|
|
573
|
+
cause,
|
|
574
|
+
})));
|
|
575
|
+
if (Option.isNone(rowOption)) {
|
|
576
|
+
return yield* new SessionUpdateClaimsError({
|
|
577
|
+
message: "Session not found",
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
yield* Effect.fromResult(validateRowAssurance(rowOption.value, now)).pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
581
|
+
message: "Session evidence policy validation failed",
|
|
582
|
+
cause,
|
|
583
|
+
})));
|
|
584
|
+
const preparedAssurance = yield* Effect.fromResult(prepareAssurance([...rowOption.value.authenticationEvents, ...asEvidence(evidence)], now)).pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
585
|
+
message: "Session evidence policy validation failed",
|
|
586
|
+
cause,
|
|
587
|
+
})));
|
|
588
|
+
const { assurance, authenticationEvents, mfaVerifiedAt } = preparedAssurance;
|
|
589
|
+
if (!assurance.primaryEstablished) {
|
|
590
|
+
return yield* new SessionUpdateClaimsError({
|
|
591
|
+
message: "Session evidence did not establish a primary factor",
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
const updated = yield* dependencies.sessionStore
|
|
595
|
+
.appendEvidence({
|
|
596
|
+
sessionId,
|
|
597
|
+
authenticationEvents,
|
|
598
|
+
authTime: assurance.authenticatedAt ?? rowOption.value.authTime,
|
|
599
|
+
aal: assurance.level,
|
|
600
|
+
amr: assurance.amr,
|
|
601
|
+
mfaVerifiedAt,
|
|
602
|
+
...(claims === undefined ? {} : { claims }),
|
|
603
|
+
})
|
|
604
|
+
.pipe(Effect.mapError((cause) => new SessionUpdateClaimsError({
|
|
605
|
+
message: "Failed to append session evidence",
|
|
606
|
+
cause,
|
|
607
|
+
})));
|
|
608
|
+
if (Option.isNone(updated)) {
|
|
609
|
+
return yield* new SessionUpdateClaimsError({
|
|
610
|
+
message: "Session not found",
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
return currentFromRow(updated.value);
|
|
614
|
+
}),
|
|
615
|
+
assureAndRotate: Effect.fn("auth.session.assure_and_rotate")(function* (input) {
|
|
616
|
+
const parsed = parseSessionToken(input.token);
|
|
617
|
+
if (parsed === undefined) {
|
|
618
|
+
return yield* new SessionRotateError({
|
|
619
|
+
message: "Invalid session token",
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
const now = yield* currentUnixMillis;
|
|
623
|
+
const current = yield* dependencies.sessionStore
|
|
624
|
+
.findById(parsed.sessionId)
|
|
625
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
626
|
+
message: "Failed to load session",
|
|
627
|
+
cause,
|
|
628
|
+
})));
|
|
629
|
+
if (Option.isNone(current) || isExpired(current.value, now, ttl)) {
|
|
630
|
+
return yield* new SessionRotateError({
|
|
631
|
+
message: "Session is not active",
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
yield* Effect.fromResult(validateRowAssurance(current.value, now)).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
635
|
+
message: "Session evidence policy validation failed",
|
|
636
|
+
cause,
|
|
637
|
+
})));
|
|
638
|
+
const expectedSecretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, parsed.secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
639
|
+
message: "Failed to hash session secret",
|
|
640
|
+
cause,
|
|
641
|
+
})));
|
|
642
|
+
const secretMatches = yield* timingSafeEqualString(dependencies.crypto, expectedSecretHash, current.value.secretHash).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
643
|
+
message: "Failed to compare session secret",
|
|
644
|
+
cause,
|
|
645
|
+
})));
|
|
646
|
+
if (!secretMatches) {
|
|
647
|
+
return yield* new SessionRotateError({
|
|
648
|
+
message: "Invalid session token",
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
const secret = yield* dependencies.crypto
|
|
652
|
+
.randomToken(sessionSecretBytes)
|
|
653
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
654
|
+
message: "Failed to generate session secret",
|
|
655
|
+
cause,
|
|
656
|
+
})));
|
|
657
|
+
const secretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
658
|
+
message: "Failed to hash session secret",
|
|
659
|
+
cause,
|
|
660
|
+
})));
|
|
661
|
+
const activeEvents = input.supersedeRecoveryEvidence === true
|
|
662
|
+
? current.value.authenticationEvents.filter((event) => event.type !== "recovery_code")
|
|
663
|
+
: current.value.authenticationEvents;
|
|
664
|
+
const preparedAssurance = yield* Effect.fromResult(prepareAssurance([...activeEvents, ...asEvidence(input.evidence)], now)).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
665
|
+
message: "Session evidence policy validation failed",
|
|
666
|
+
cause,
|
|
667
|
+
})));
|
|
668
|
+
const { assurance, authenticationEvents, mfaVerifiedAt } = preparedAssurance;
|
|
669
|
+
if (!assurance.primaryEstablished) {
|
|
670
|
+
return yield* new SessionRotateError({
|
|
671
|
+
message: "Session evidence did not establish a primary factor",
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
const updated = yield* dependencies.sessionStore
|
|
675
|
+
.assureAndRotate({
|
|
676
|
+
sessionId: parsed.sessionId,
|
|
677
|
+
expectedSecretHash,
|
|
678
|
+
expectedAuthenticationEvents: current.value.authenticationEvents,
|
|
679
|
+
secretHash,
|
|
680
|
+
rotatedAt: now,
|
|
681
|
+
now,
|
|
682
|
+
authenticationEvents,
|
|
683
|
+
authTime: assurance.authenticatedAt ?? current.value.authTime,
|
|
684
|
+
aal: assurance.level,
|
|
685
|
+
amr: assurance.amr,
|
|
686
|
+
mfaVerifiedAt,
|
|
687
|
+
...(input.claims === undefined ? {} : { claims: input.claims }),
|
|
688
|
+
})
|
|
689
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
690
|
+
message: "Failed to update session assurance",
|
|
691
|
+
cause,
|
|
692
|
+
})));
|
|
693
|
+
if (Option.isNone(updated)) {
|
|
694
|
+
return yield* new SessionRotateError({
|
|
695
|
+
message: "Session changed or is not active",
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
return issuedFromRow(updated.value, makeSessionToken(parsed.sessionId, secret));
|
|
699
|
+
}),
|
|
353
700
|
listForUser: Effect.fn("auth.session.list_for_user")(function* (input) {
|
|
354
701
|
const now = yield* currentUnixMillis;
|
|
355
702
|
const rows = yield* dependencies.sessionStore.listByUser(input).pipe(Effect.mapError((cause) => new SessionListError({
|
|
356
703
|
message: "Failed to list user sessions",
|
|
357
704
|
cause,
|
|
358
705
|
})));
|
|
706
|
+
for (const row of rows) {
|
|
707
|
+
if (isExpired(row, now, ttl)) {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
yield* Effect.fromResult(validateRowAssurance(row, now)).pipe(Effect.mapError((cause) => new SessionListError({
|
|
711
|
+
message: "Session evidence policy validation failed",
|
|
712
|
+
cause,
|
|
713
|
+
})));
|
|
714
|
+
}
|
|
359
715
|
return activeSessionsForUser(rows, now, ttl);
|
|
360
716
|
}),
|
|
361
717
|
revoke: Effect.fn("auth.session.revoke")(function* (input) {
|
|
@@ -426,10 +782,194 @@ export const makeSessions = (dependencies) => {
|
|
|
426
782
|
}),
|
|
427
783
|
});
|
|
428
784
|
};
|
|
785
|
+
export const makeTotpSessionRotation = (dependencies) => {
|
|
786
|
+
const ttl = dependencies.ttl ?? defaultSessionTtlPolicy;
|
|
787
|
+
const sessionSecretBytes = dependencies.sessionSecretBytes ?? 32;
|
|
788
|
+
const customEvidencePolicies = dependencies.customEvidencePolicies ?? emptyCustomEvidencePolicyRegistry;
|
|
789
|
+
return TotpSessionRotation.of({
|
|
790
|
+
acceptAndRotate: Effect.fn("auth.totp.accept_and_rotate")(function* (input) {
|
|
791
|
+
const parsed = parseSessionToken(input.token);
|
|
792
|
+
if (parsed === undefined) {
|
|
793
|
+
return yield* new SessionRotateError({
|
|
794
|
+
message: "Invalid session token",
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
const now = yield* currentUnixMillis;
|
|
798
|
+
const expectedSecretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, parsed.secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
799
|
+
message: "Failed to hash session secret",
|
|
800
|
+
cause,
|
|
801
|
+
})));
|
|
802
|
+
const secret = yield* dependencies.crypto
|
|
803
|
+
.randomToken(sessionSecretBytes)
|
|
804
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
805
|
+
message: "Failed to generate session secret",
|
|
806
|
+
cause,
|
|
807
|
+
})));
|
|
808
|
+
const secretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
809
|
+
message: "Failed to hash session secret",
|
|
810
|
+
cause,
|
|
811
|
+
})));
|
|
812
|
+
const preparedAssurance = yield* Effect.fromResult(prepareSessionAssuranceResult([
|
|
813
|
+
...input.expectedAuthenticationEvents,
|
|
814
|
+
...asEvidence(input.evidence),
|
|
815
|
+
], customEvidencePolicies, now)).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
816
|
+
message: "Session evidence policy validation failed",
|
|
817
|
+
cause,
|
|
818
|
+
})));
|
|
819
|
+
const { assurance, authenticationEvents, mfaVerifiedAt } = preparedAssurance;
|
|
820
|
+
if (!assurance.primaryEstablished) {
|
|
821
|
+
return yield* new SessionRotateError({
|
|
822
|
+
message: "Session evidence did not establish a primary factor",
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
const updated = yield* dependencies.store
|
|
826
|
+
.acceptAndRotate({
|
|
827
|
+
factorId: input.factorId,
|
|
828
|
+
userId: input.userId,
|
|
829
|
+
counter: input.acceptedCounter,
|
|
830
|
+
lastUsedAt: now,
|
|
831
|
+
...(input.factorMetadata === undefined
|
|
832
|
+
? {}
|
|
833
|
+
: { factorMetadata: input.factorMetadata }),
|
|
834
|
+
sessionId: parsed.sessionId,
|
|
835
|
+
expectedSecretHash,
|
|
836
|
+
expectedAuthenticationEvents: input.expectedAuthenticationEvents,
|
|
837
|
+
secretHash,
|
|
838
|
+
rotatedAt: now,
|
|
839
|
+
now,
|
|
840
|
+
authenticationEvents,
|
|
841
|
+
authTime: assurance.authenticatedAt ?? now,
|
|
842
|
+
aal: assurance.level,
|
|
843
|
+
amr: assurance.amr,
|
|
844
|
+
mfaVerifiedAt,
|
|
845
|
+
...(input.claims === undefined ? {} : { claims: input.claims }),
|
|
846
|
+
})
|
|
847
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
848
|
+
message: "Failed to accept TOTP counter",
|
|
849
|
+
cause,
|
|
850
|
+
})));
|
|
851
|
+
if (Option.isNone(updated) || isExpired(updated.value, now, ttl)) {
|
|
852
|
+
return yield* new SessionRotateError({
|
|
853
|
+
message: "Session or TOTP factor changed",
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
return issuedFromRow(updated.value, makeSessionToken(parsed.sessionId, secret));
|
|
857
|
+
}),
|
|
858
|
+
});
|
|
859
|
+
};
|
|
860
|
+
export const makeRecoveryCodeSessionRotation = (dependencies) => {
|
|
861
|
+
const ttl = dependencies.ttl ?? defaultSessionTtlPolicy;
|
|
862
|
+
const sessionSecretBytes = dependencies.sessionSecretBytes ?? 32;
|
|
863
|
+
const customEvidencePolicies = dependencies.customEvidencePolicies ?? emptyCustomEvidencePolicyRegistry;
|
|
864
|
+
return RecoveryCodeSessionRotation.of({
|
|
865
|
+
consumeAndRotate: Effect.fn("auth.recovery_code.consume_and_rotate")(function* (input) {
|
|
866
|
+
const parsed = parseSessionToken(input.token);
|
|
867
|
+
if (parsed === undefined) {
|
|
868
|
+
return yield* new SessionRotateError({
|
|
869
|
+
message: "Invalid session token",
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
const now = yield* currentUnixMillis;
|
|
873
|
+
const expectedSecretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, parsed.secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
874
|
+
message: "Failed to hash session secret",
|
|
875
|
+
cause,
|
|
876
|
+
})));
|
|
877
|
+
const secret = yield* dependencies.crypto
|
|
878
|
+
.randomToken(sessionSecretBytes)
|
|
879
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
880
|
+
message: "Failed to generate session secret",
|
|
881
|
+
cause,
|
|
882
|
+
})));
|
|
883
|
+
const secretHash = yield* hashSessionSecret(dependencies.crypto, dependencies.secret, secret).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
884
|
+
message: "Failed to hash session secret",
|
|
885
|
+
cause,
|
|
886
|
+
})));
|
|
887
|
+
const preparedAssurance = yield* Effect.fromResult(prepareSessionAssuranceResult([
|
|
888
|
+
...input.expectedAuthenticationEvents,
|
|
889
|
+
...asEvidence(input.evidence),
|
|
890
|
+
], customEvidencePolicies, now)).pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
891
|
+
message: "Session evidence policy validation failed",
|
|
892
|
+
cause,
|
|
893
|
+
})));
|
|
894
|
+
const { assurance, authenticationEvents, mfaVerifiedAt } = preparedAssurance;
|
|
895
|
+
if (!assurance.primaryEstablished) {
|
|
896
|
+
return yield* new SessionRotateError({
|
|
897
|
+
message: "Session evidence did not establish a primary factor",
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
const updated = yield* dependencies.store
|
|
901
|
+
.consumeAndRotate({
|
|
902
|
+
codeId: input.codeId,
|
|
903
|
+
userId: input.userId,
|
|
904
|
+
usedAt: now,
|
|
905
|
+
...(input.codeMetadata === undefined
|
|
906
|
+
? {}
|
|
907
|
+
: { codeMetadata: input.codeMetadata }),
|
|
908
|
+
sessionId: parsed.sessionId,
|
|
909
|
+
expectedSecretHash,
|
|
910
|
+
expectedAuthenticationEvents: input.expectedAuthenticationEvents,
|
|
911
|
+
secretHash,
|
|
912
|
+
rotatedAt: now,
|
|
913
|
+
now,
|
|
914
|
+
authenticationEvents,
|
|
915
|
+
authTime: assurance.authenticatedAt ?? now,
|
|
916
|
+
aal: assurance.level,
|
|
917
|
+
amr: assurance.amr,
|
|
918
|
+
mfaVerifiedAt,
|
|
919
|
+
...(input.claims === undefined ? {} : { claims: input.claims }),
|
|
920
|
+
})
|
|
921
|
+
.pipe(Effect.mapError((cause) => new SessionRotateError({
|
|
922
|
+
message: "Failed to consume recovery code",
|
|
923
|
+
cause,
|
|
924
|
+
})));
|
|
925
|
+
if (Option.isNone(updated) || isExpired(updated.value, now, ttl)) {
|
|
926
|
+
return yield* new SessionRotateError({
|
|
927
|
+
message: "Session changed or is not active",
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
return issuedFromRow(updated.value, makeSessionToken(parsed.sessionId, secret));
|
|
931
|
+
}),
|
|
932
|
+
});
|
|
933
|
+
};
|
|
934
|
+
export function RecoveryCodeSessionRotationLive(options) {
|
|
935
|
+
return Layer.effect(RecoveryCodeSessionRotation)(Effect.gen(function* () {
|
|
936
|
+
const crypto = yield* Crypto;
|
|
937
|
+
const store = yield* RecoveryCodeSessionRotateStore;
|
|
938
|
+
const customEvidencePolicies = yield* Effect.serviceOption(CustomEvidencePolicies);
|
|
939
|
+
const resolved = options ?? { secret: (yield* AuthSecrets).session };
|
|
940
|
+
return makeRecoveryCodeSessionRotation({
|
|
941
|
+
...resolved,
|
|
942
|
+
crypto,
|
|
943
|
+
store,
|
|
944
|
+
...(resolved.customEvidencePolicies === undefined &&
|
|
945
|
+
Option.isSome(customEvidencePolicies)
|
|
946
|
+
? { customEvidencePolicies: customEvidencePolicies.value }
|
|
947
|
+
: {}),
|
|
948
|
+
});
|
|
949
|
+
}));
|
|
950
|
+
}
|
|
951
|
+
export function TotpSessionRotationLive(options) {
|
|
952
|
+
return Layer.effect(TotpSessionRotation)(Effect.gen(function* () {
|
|
953
|
+
const crypto = yield* Crypto;
|
|
954
|
+
const store = yield* TotpSessionRotateStore;
|
|
955
|
+
const customEvidencePolicies = yield* Effect.serviceOption(CustomEvidencePolicies);
|
|
956
|
+
const resolved = options ?? { secret: (yield* AuthSecrets).session };
|
|
957
|
+
return makeTotpSessionRotation({
|
|
958
|
+
...resolved,
|
|
959
|
+
crypto,
|
|
960
|
+
store,
|
|
961
|
+
...(resolved.customEvidencePolicies === undefined &&
|
|
962
|
+
Option.isSome(customEvidencePolicies)
|
|
963
|
+
? { customEvidencePolicies: customEvidencePolicies.value }
|
|
964
|
+
: {}),
|
|
965
|
+
});
|
|
966
|
+
}));
|
|
967
|
+
}
|
|
429
968
|
export function SessionsLive(options) {
|
|
430
969
|
return Layer.effect(Sessions)(Effect.gen(function* () {
|
|
431
970
|
const crypto = yield* Crypto;
|
|
432
971
|
const sessionStore = yield* SessionStore;
|
|
972
|
+
const customEvidencePolicies = yield* Effect.serviceOption(CustomEvidencePolicies);
|
|
433
973
|
const resolvedOptions = options ??
|
|
434
974
|
{
|
|
435
975
|
...(yield* AuthSessionsConfig),
|
|
@@ -439,27 +979,25 @@ export function SessionsLive(options) {
|
|
|
439
979
|
...resolvedOptions,
|
|
440
980
|
crypto,
|
|
441
981
|
sessionStore,
|
|
982
|
+
...(resolvedOptions.customEvidencePolicies === undefined &&
|
|
983
|
+
Option.isSome(customEvidencePolicies)
|
|
984
|
+
? { customEvidencePolicies: customEvidencePolicies.value }
|
|
985
|
+
: {}),
|
|
442
986
|
});
|
|
443
987
|
}));
|
|
444
988
|
}
|
|
445
989
|
export const upgradeCurrentSession = (input) => Effect.gen(function* () {
|
|
446
990
|
const current = yield* CurrentSession;
|
|
447
991
|
const sessions = yield* Sessions;
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
...(input.claims === undefined ? {} : { claims: input.claims }),
|
|
455
|
-
reason: input.reason ?? "mfa_verified",
|
|
456
|
-
});
|
|
992
|
+
return yield* sessions.appendEvidence(current.sessionId, input.evidence, input.claims);
|
|
993
|
+
});
|
|
994
|
+
export const reauthenticateCurrentSession = (input) => Effect.gen(function* () {
|
|
995
|
+
const current = yield* CurrentSession;
|
|
996
|
+
const sessions = yield* Sessions;
|
|
997
|
+
return yield* sessions.appendEvidence(current.sessionId, input.evidence, input.claims);
|
|
457
998
|
});
|
|
458
999
|
export class SessionCookie extends Context.Service()("auth/SessionCookie") {
|
|
459
1000
|
}
|
|
460
|
-
(function (SessionCookie) {
|
|
461
|
-
SessionCookie.make = (service) => SessionCookie.of(service);
|
|
462
|
-
})(SessionCookie || (SessionCookie = {}));
|
|
463
1001
|
export const defaultSessionCookieOptions = {
|
|
464
1002
|
name: "__Host-session",
|
|
465
1003
|
secure: true,
|
|
@@ -542,7 +1080,7 @@ const parseCookieHeader = (header, name) => {
|
|
|
542
1080
|
};
|
|
543
1081
|
export const makeSessionCookie = (options) => {
|
|
544
1082
|
const resolved = resolveSessionCookieOptions(options);
|
|
545
|
-
return SessionCookie.
|
|
1083
|
+
return SessionCookie.of({
|
|
546
1084
|
read: Effect.fn("auth.session_cookie.read")((request) => Effect.succeed(parseCookieHeader(request.headers.get("Cookie"), resolved.name))),
|
|
547
1085
|
commit: Effect.fn("auth.session_cookie.commit")((issued) => Effect.succeed(serializeSessionCookie(resolved, issued.token, issued.expiresAt))),
|
|
548
1086
|
clear: Effect.fn("auth.session_cookie.clear")(() => Effect.succeed(serializeClearSessionCookie(resolved)))(),
|
|
@@ -554,12 +1092,6 @@ export const SessionCookieLive = (options) => Layer.effect(SessionCookie)(Effect
|
|
|
554
1092
|
}));
|
|
555
1093
|
export class CurrentSession extends Context.Service()("auth/CurrentSession") {
|
|
556
1094
|
}
|
|
557
|
-
(function (CurrentSession) {
|
|
558
|
-
CurrentSession.make = (service) => CurrentSession.of(service);
|
|
559
|
-
})(CurrentSession || (CurrentSession = {}));
|
|
560
1095
|
export class CurrentActor extends Context.Service()("auth/CurrentActor") {
|
|
561
1096
|
}
|
|
562
|
-
(function (CurrentActor) {
|
|
563
|
-
CurrentActor.make = (service) => CurrentActor.of(service);
|
|
564
|
-
})(CurrentActor || (CurrentActor = {}));
|
|
565
1097
|
//# sourceMappingURL=Sessions.js.map
|