@effect-auth/core 0.1.0-alpha.1 → 0.1.0-alpha.13

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 (255) hide show
  1. package/README.md +790 -73
  2. package/dist/ApiKey.d.ts +207 -0
  3. package/dist/ApiKey.d.ts.map +1 -0
  4. package/dist/ApiKey.js +275 -0
  5. package/dist/ApiKey.js.map +1 -0
  6. package/dist/AuditLog.d.ts +335 -1
  7. package/dist/AuditLog.d.ts.map +1 -1
  8. package/dist/AuditLog.js +318 -1
  9. package/dist/AuditLog.js.map +1 -1
  10. package/dist/AuthConfig.d.ts +42 -0
  11. package/dist/AuthConfig.d.ts.map +1 -0
  12. package/dist/AuthConfig.js +43 -0
  13. package/dist/AuthConfig.js.map +1 -0
  14. package/dist/AuthFlow.d.ts +462 -36
  15. package/dist/AuthFlow.d.ts.map +1 -1
  16. package/dist/AuthFlow.js +657 -5
  17. package/dist/AuthFlow.js.map +1 -1
  18. package/dist/AuthKernel.d.ts +3 -0
  19. package/dist/AuthKernel.d.ts.map +1 -0
  20. package/dist/AuthKernel.js +9 -0
  21. package/dist/AuthKernel.js.map +1 -0
  22. package/dist/Challenge.d.ts +24 -4
  23. package/dist/Challenge.d.ts.map +1 -1
  24. package/dist/Challenge.js +167 -1
  25. package/dist/Challenge.js.map +1 -1
  26. package/dist/Client.d.ts +449 -0
  27. package/dist/Client.d.ts.map +1 -0
  28. package/dist/Client.js +985 -0
  29. package/dist/Client.js.map +1 -0
  30. package/dist/Crypto.d.ts +6 -1
  31. package/dist/Crypto.d.ts.map +1 -1
  32. package/dist/Crypto.js +62 -1
  33. package/dist/Crypto.js.map +1 -1
  34. package/dist/DomainVerification.d.ts +200 -0
  35. package/dist/DomainVerification.d.ts.map +1 -0
  36. package/dist/DomainVerification.js +304 -0
  37. package/dist/DomainVerification.js.map +1 -0
  38. package/dist/EffectQbSqliteStorage.d.ts +985 -0
  39. package/dist/EffectQbSqliteStorage.d.ts.map +1 -0
  40. package/dist/EffectQbSqliteStorage.js +2824 -0
  41. package/dist/EffectQbSqliteStorage.js.map +1 -0
  42. package/dist/EmailOtp.d.ts +120 -0
  43. package/dist/EmailOtp.d.ts.map +1 -0
  44. package/dist/EmailOtp.js +286 -0
  45. package/dist/EmailOtp.js.map +1 -0
  46. package/dist/EmailVerification.d.ts +121 -0
  47. package/dist/EmailVerification.d.ts.map +1 -0
  48. package/dist/EmailVerification.js +200 -0
  49. package/dist/EmailVerification.js.map +1 -0
  50. package/dist/HttpApi/Api.d.ts +2410 -0
  51. package/dist/HttpApi/Api.d.ts.map +1 -0
  52. package/dist/HttpApi/Api.js +3026 -0
  53. package/dist/HttpApi/Api.js.map +1 -0
  54. package/dist/HttpApi/Endpoints.d.ts +1073 -0
  55. package/dist/HttpApi/Endpoints.d.ts.map +1 -0
  56. package/dist/HttpApi/Endpoints.js +428 -0
  57. package/dist/HttpApi/Endpoints.js.map +1 -0
  58. package/dist/HttpApi/Errors.d.ts +114 -0
  59. package/dist/HttpApi/Errors.d.ts.map +1 -0
  60. package/dist/HttpApi/Errors.js +230 -0
  61. package/dist/HttpApi/Errors.js.map +1 -0
  62. package/dist/HttpApi/Schemas.d.ts +1254 -0
  63. package/dist/HttpApi/Schemas.d.ts.map +1 -0
  64. package/dist/HttpApi/Schemas.js +862 -0
  65. package/dist/HttpApi/Schemas.js.map +1 -0
  66. package/dist/HttpApi/Security.d.ts +159 -0
  67. package/dist/HttpApi/Security.d.ts.map +1 -0
  68. package/dist/HttpApi/Security.js +530 -0
  69. package/dist/HttpApi/Security.js.map +1 -0
  70. package/dist/HttpApi/Transport.d.ts +65 -0
  71. package/dist/HttpApi/Transport.d.ts.map +1 -0
  72. package/dist/HttpApi/Transport.js +311 -0
  73. package/dist/HttpApi/Transport.js.map +1 -0
  74. package/dist/HttpApi/index.d.ts +8 -0
  75. package/dist/HttpApi/index.d.ts.map +1 -0
  76. package/dist/HttpApi/index.js +7 -0
  77. package/dist/HttpApi/index.js.map +1 -0
  78. package/dist/HttpApi.d.ts +2 -0
  79. package/dist/HttpApi.d.ts.map +1 -0
  80. package/dist/HttpApi.js +2 -0
  81. package/dist/HttpApi.js.map +1 -0
  82. package/dist/Identifiers.d.ts +3 -0
  83. package/dist/Identifiers.d.ts.map +1 -1
  84. package/dist/Identifiers.js +2 -0
  85. package/dist/Identifiers.js.map +1 -1
  86. package/dist/IncidentAction.d.ts +80 -0
  87. package/dist/IncidentAction.d.ts.map +1 -0
  88. package/dist/IncidentAction.js +158 -0
  89. package/dist/IncidentAction.js.map +1 -0
  90. package/dist/Internal.d.ts +7 -0
  91. package/dist/Internal.d.ts.map +1 -0
  92. package/dist/Internal.js +12 -0
  93. package/dist/Internal.js.map +1 -0
  94. package/dist/Jwt.d.ts +281 -0
  95. package/dist/Jwt.d.ts.map +1 -0
  96. package/dist/Jwt.js +721 -0
  97. package/dist/Jwt.js.map +1 -0
  98. package/dist/LoginApproval.d.ts +314 -0
  99. package/dist/LoginApproval.d.ts.map +1 -0
  100. package/dist/LoginApproval.js +551 -0
  101. package/dist/LoginApproval.js.map +1 -0
  102. package/dist/LoginNotification.d.ts +183 -0
  103. package/dist/LoginNotification.d.ts.map +1 -0
  104. package/dist/LoginNotification.js +329 -0
  105. package/dist/LoginNotification.js.map +1 -0
  106. package/dist/LoginRisk.d.ts +344 -0
  107. package/dist/LoginRisk.d.ts.map +1 -0
  108. package/dist/LoginRisk.js +484 -0
  109. package/dist/LoginRisk.js.map +1 -0
  110. package/dist/MachineAuth.d.ts +73 -0
  111. package/dist/MachineAuth.d.ts.map +1 -0
  112. package/dist/MachineAuth.js +147 -0
  113. package/dist/MachineAuth.js.map +1 -0
  114. package/dist/MagicLink.d.ts +85 -0
  115. package/dist/MagicLink.d.ts.map +1 -0
  116. package/dist/MagicLink.js +206 -0
  117. package/dist/MagicLink.js.map +1 -0
  118. package/dist/Mailer.d.ts +147 -0
  119. package/dist/Mailer.d.ts.map +1 -0
  120. package/dist/Mailer.js +208 -0
  121. package/dist/Mailer.js.map +1 -0
  122. package/dist/OAuth.d.ts +1890 -0
  123. package/dist/OAuth.d.ts.map +1 -0
  124. package/dist/OAuth.js +3063 -0
  125. package/dist/OAuth.js.map +1 -0
  126. package/dist/Passkey.d.ts +334 -0
  127. package/dist/Passkey.d.ts.map +1 -0
  128. package/dist/Passkey.js +422 -0
  129. package/dist/Passkey.js.map +1 -0
  130. package/dist/PasskeySimpleWebAuthn.d.ts +11 -0
  131. package/dist/PasskeySimpleWebAuthn.d.ts.map +1 -0
  132. package/dist/PasskeySimpleWebAuthn.js +181 -0
  133. package/dist/PasskeySimpleWebAuthn.js.map +1 -0
  134. package/dist/Password.d.ts +237 -0
  135. package/dist/Password.d.ts.map +1 -0
  136. package/dist/Password.js +641 -0
  137. package/dist/Password.js.map +1 -0
  138. package/dist/Policy.d.ts +7 -4
  139. package/dist/Policy.d.ts.map +1 -1
  140. package/dist/Policy.js +28 -5
  141. package/dist/Policy.js.map +1 -1
  142. package/dist/Privacy.d.ts +15 -0
  143. package/dist/Privacy.d.ts.map +1 -1
  144. package/dist/Privacy.js +58 -1
  145. package/dist/Privacy.js.map +1 -1
  146. package/dist/RateLimiter.d.ts +104 -0
  147. package/dist/RateLimiter.d.ts.map +1 -0
  148. package/dist/RateLimiter.js +118 -0
  149. package/dist/RateLimiter.js.map +1 -0
  150. package/dist/RecoveryCode.d.ts +169 -0
  151. package/dist/RecoveryCode.d.ts.map +1 -0
  152. package/dist/RecoveryCode.js +299 -0
  153. package/dist/RecoveryCode.js.map +1 -0
  154. package/dist/RefreshToken.d.ts +222 -0
  155. package/dist/RefreshToken.d.ts.map +1 -0
  156. package/dist/RefreshToken.js +342 -0
  157. package/dist/RefreshToken.js.map +1 -0
  158. package/dist/Retention.d.ts +98 -0
  159. package/dist/Retention.d.ts.map +1 -0
  160. package/dist/Retention.js +204 -0
  161. package/dist/Retention.js.map +1 -0
  162. package/dist/SecurityTimeline.d.ts +78 -0
  163. package/dist/SecurityTimeline.d.ts.map +1 -0
  164. package/dist/SecurityTimeline.js +461 -0
  165. package/dist/SecurityTimeline.js.map +1 -0
  166. package/dist/Sessions.d.ts +123 -11
  167. package/dist/Sessions.d.ts.map +1 -1
  168. package/dist/Sessions.js +534 -1
  169. package/dist/Sessions.js.map +1 -1
  170. package/dist/StepUp.d.ts +44 -0
  171. package/dist/StepUp.d.ts.map +1 -0
  172. package/dist/StepUp.js +82 -0
  173. package/dist/StepUp.js.map +1 -0
  174. package/dist/Storage.d.ts +73 -5
  175. package/dist/Storage.d.ts.map +1 -1
  176. package/dist/Storage.js +11 -1
  177. package/dist/Storage.js.map +1 -1
  178. package/dist/StorageMigrations.d.ts +23 -1
  179. package/dist/StorageMigrations.d.ts.map +1 -1
  180. package/dist/StorageMigrations.js +462 -2
  181. package/dist/StorageMigrations.js.map +1 -1
  182. package/dist/Testing.d.ts +9 -1
  183. package/dist/Testing.d.ts.map +1 -1
  184. package/dist/Testing.js +30 -2
  185. package/dist/Testing.js.map +1 -1
  186. package/dist/Totp.d.ts +220 -0
  187. package/dist/Totp.d.ts.map +1 -0
  188. package/dist/Totp.js +477 -0
  189. package/dist/Totp.js.map +1 -0
  190. package/dist/TrustedDevice.d.ts +127 -0
  191. package/dist/TrustedDevice.d.ts.map +1 -0
  192. package/dist/TrustedDevice.js +252 -0
  193. package/dist/TrustedDevice.js.map +1 -0
  194. package/dist/WaitUntil.d.ts.map +1 -1
  195. package/dist/WaitUntil.js +1 -1
  196. package/dist/WaitUntil.js.map +1 -1
  197. package/dist/Webhook.d.ts +380 -0
  198. package/dist/Webhook.d.ts.map +1 -0
  199. package/dist/Webhook.js +592 -0
  200. package/dist/Webhook.js.map +1 -0
  201. package/dist/alchemy/cloudflare/Email.d.ts +25 -0
  202. package/dist/alchemy/cloudflare/Email.d.ts.map +1 -0
  203. package/dist/alchemy/cloudflare/Email.js +117 -0
  204. package/dist/alchemy/cloudflare/Email.js.map +1 -0
  205. package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts +34 -0
  206. package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
  207. package/dist/alchemy/cloudflare/RateLimitDurableObject.js +30 -0
  208. package/dist/alchemy/cloudflare/RateLimitDurableObject.js.map +1 -0
  209. package/dist/cloudflare/Email.d.ts +25 -0
  210. package/dist/cloudflare/Email.d.ts.map +1 -0
  211. package/dist/cloudflare/Email.js +153 -0
  212. package/dist/cloudflare/Email.js.map +1 -0
  213. package/dist/cloudflare/RateLimitDurableObject.d.ts +50 -0
  214. package/dist/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
  215. package/dist/cloudflare/RateLimitDurableObject.js +51 -0
  216. package/dist/cloudflare/RateLimitDurableObject.js.map +1 -0
  217. package/dist/index.d.ts +25 -0
  218. package/dist/index.d.ts.map +1 -1
  219. package/dist/index.js +25 -0
  220. package/dist/index.js.map +1 -1
  221. package/dist/internal/RateLimitDurableObject.d.ts +32 -0
  222. package/dist/internal/RateLimitDurableObject.d.ts.map +1 -0
  223. package/dist/internal/RateLimitDurableObject.js +80 -0
  224. package/dist/internal/RateLimitDurableObject.js.map +1 -0
  225. package/migrations/0002_auth_password.sql +25 -0
  226. package/migrations/0003_auth_login_approval_review.sql +22 -0
  227. package/migrations/0004_auth_trusted_device.sql +12 -0
  228. package/migrations/0005_auth_passkey.sql +17 -0
  229. package/migrations/0006_auth_totp_factor.sql +17 -0
  230. package/migrations/0007_auth_recovery_code.sql +13 -0
  231. package/migrations/0008_auth_api_key.sql +17 -0
  232. package/migrations/0009_auth_refresh_token.sql +21 -0
  233. package/migrations/0010_auth_jwt_revocation.sql +8 -0
  234. package/migrations/0011_auth_oauth_account.sql +16 -0
  235. package/migrations/0012_auth_oauth_provider_token_vault.sql +20 -0
  236. package/migrations/0013_auth_security_timeline.sql +16 -0
  237. package/migrations/0014_auth_webhook_outbox.sql +16 -0
  238. package/migrations/0015_auth_webhook_replay.sql +7 -0
  239. package/migrations/0016_auth_login_risk_history.sql +23 -0
  240. package/migrations/0017_auth_audit_log.sql +17 -0
  241. package/migrations/0018_auth_domain_verification.sql +18 -0
  242. package/migrations/0019_auth_oauth_authorization_code.sql +17 -0
  243. package/migrations/0020_auth_oauth_provider_mode_token.sql +24 -0
  244. package/migrations/0021_auth_oauth_client_secret.sql +14 -0
  245. package/migrations/0022_auth_oauth_client.sql +15 -0
  246. package/migrations/0023_auth_oauth_consent.sql +15 -0
  247. package/package.json +162 -26
  248. package/dist/D1Kysely.d.ts +0 -40
  249. package/dist/D1Kysely.d.ts.map +0 -1
  250. package/dist/D1Kysely.js +0 -75
  251. package/dist/D1Kysely.js.map +0 -1
  252. package/dist/KyselyStorage.d.ts +0 -41
  253. package/dist/KyselyStorage.d.ts.map +0 -1
  254. package/dist/KyselyStorage.js +0 -176
  255. package/dist/KyselyStorage.js.map +0 -1
@@ -0,0 +1,3026 @@
1
+ import { Context, Effect, Encoding, Layer, Option, Redacted, Result } from "effect";
2
+ import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
3
+ import { HttpApi, HttpApiBuilder, HttpApiGroup } from "effect/unstable/httpapi";
4
+ import { ApiKeyId } from "../ApiKey.js";
5
+ import { Jwks } from "../Jwt.js";
6
+ import { AuthFlow, AuthFlowState, AuthResult, LoginApprovalFinalize, } from "../AuthFlow.js";
7
+ import { EmailOtpLogin } from "../EmailOtp.js";
8
+ import { EmailDeliveryError, EmailVerification, EmailVerificationFlow, EmailVerificationIssueError, } from "../EmailVerification.js";
9
+ import { OAuthClientId as makeOAuthClientId } from "../Identifiers.js";
10
+ import { currentUnixMillis } from "../Internal.js";
11
+ import { LoginApproval, LoginApprovalReview } from "../LoginApproval.js";
12
+ import { LoginNotification } from "../LoginNotification.js";
13
+ import { MagicLinkLogin } from "../MagicLink.js";
14
+ import { OAuthAuthorizationCode, OAuthAuthorizationCodeTokenGrant, OAuthClientCredentialsGrant, OAuthProviderAuthorization, OAuthRefreshToken, OAuthRefreshTokenGrant, OAuthTokenIntrospection, OAuthTokenRevocation, OAuthCodeVerifier as makeOAuthCodeVerifier, } from "../OAuth.js";
15
+ import { PasswordLogin, PasswordManagement, PasswordRegistration, PasswordReset, } from "../Password.js";
16
+ import { PasskeyCredentialId } from "../Passkey.js";
17
+ import { CurrentSession, SessionCookie, Sessions, sessionRequestMetadataKey, upgradeCurrentSession, } from "../Sessions.js";
18
+ import { SecurityTimelineStore } from "../SecurityTimeline.js";
19
+ import { UserStore } from "../Storage.js";
20
+ import { TrustedDevice, TrustedDeviceCookie, TrustedDeviceStore, } from "../TrustedDevice.js";
21
+ import { adminSecurityTimelineListEndpoint, adminSessionListEndpoint, adminSessionRevokeAllEndpoint, adminSessionRevokeEndpoint, adminTrustedDeviceListEndpoint, adminTrustedDeviceRevokeEndpoint, apiKeyCreateEndpoint, apiKeyListEndpoint, apiKeyRevokeEndpoint, currentSessionEndpoint, emailOtpStartEndpoint, emailOtpVerifyEndpoint, emailVerificationStartEndpoint, emailVerificationVerifyEndpoint, loginApprovalApproveEndpoint, loginApprovalFinalizeEndpoint, loginApprovalStatusEndpoint, loginNotificationReportEndpoint, jwtIntrospectEndpoint, jwtJwksEndpoint, jwtRevokeEndpoint, listSessionsEndpoint, logoutEndpoint, magicLinkStartEndpoint, magicLinkVerifyEndpoint, mfaOptionsEndpoint, oauthAccountUnlinkEndpoint, oauthAuthorizationStartEndpoint, oauthLinkConfirmationConfirmEndpoint, oauthLinkConfirmationInspectEndpoint, oauthLinkConfirmationStartEndpoint, oauthProviderAuthorizeEndpoint, oauthTokenEndpoint, oauthTokenIntrospectionEndpoint, oauthTokenRevocationEndpoint, oidcDiscoveryMetadataEndpoint, passwordChangeEndpoint, passwordResetStartEndpoint, passwordResetVerifyEndpoint, passwordSetEndpoint, passwordSignInEndpoint, passwordSignUpEndpoint, passkeyMfaStartEndpoint, passkeyMfaVerifyEndpoint, recoveryCodeMfaVerifyEndpoint, recoveryCodeMfaVerifyForFlowEndpoint, refreshTokenRefreshEndpoint, refreshSessionEndpoint, revokeOtherSessionsEndpoint, revokeSessionEndpoint, securityTimelineListEndpoint, stepUpOptionsEndpoint, stepUpPasskeyStartEndpoint, stepUpPasskeyVerifyEndpoint, stepUpRecoveryCodeVerifyEndpoint, stepUpTotpVerifyEndpoint, trustedDeviceListEndpoint, trustedDeviceRevokeEndpoint, totpMfaVerifyEndpoint, totpMfaVerifyForFlowEndpoint, } from "./Endpoints.js";
22
+ import { AuthBadRequestError, AuthEmailAlreadyRegisteredError, AuthInternalError, AuthInvalidCredentialsError, AuthPolicyDeniedError, AuthRateLimitedError, AuthSchemaErrorMiddleware, AuthSchemaErrorMiddlewareLive, AuthUnauthenticatedError, OAuthAuthorizationEndpointError, OAuthTokenEndpointError, OAuthTokenIntrospectionEndpointError, OAuthTokenRevocationEndpointError, } from "./Errors.js";
23
+ import { OAuthProviderAuthorizationQuery, OAuthTokenRequestBody, OAuthTokenIntrospectionRequestBody, OAuthTokenIntrospectionResponseBody, OAuthTokenRevocationRequestBody, } from "./Schemas.js";
24
+ import { AuthApiRateLimit, AuthApiRateLimitLive, AuthApiRateLimitNoopLive, AuthHttpApiConfig, AuthOriginCheckMiddleware, AuthOriginCheckMiddlewareConfigLive, AuthRateLimitMiddleware, makeAuthRequestMetadata, } from "./Security.js";
25
+ import { AuthHttp, LoginApprovalPendingCookie, makeLoginApprovalPendingCookie, } from "./Transport.js";
26
+ const canStartRequiredEmailVerification = (result) => result._tag === "RequiresEmailVerification" &&
27
+ result.userId !== undefined &&
28
+ result.email !== undefined;
29
+ const noopAuthApiRateLimit = AuthApiRateLimit.make({
30
+ request: () => Effect.void,
31
+ passwordSignIn: () => Effect.void,
32
+ passwordSignUp: () => Effect.void,
33
+ passwordResetStart: () => Effect.void,
34
+ emailOtpStart: () => Effect.void,
35
+ magicLinkStart: () => Effect.void,
36
+ emailVerificationStart: () => Effect.void,
37
+ });
38
+ export const passwordSignInInput = (payload, trustedDeviceToken, request) => ({
39
+ ...payload,
40
+ password: Redacted.make(payload.password),
41
+ ...(trustedDeviceToken === undefined ? {} : { trustedDeviceToken }),
42
+ ...(request === undefined ? {} : { request }),
43
+ });
44
+ export const passwordSignUpInput = (payload, request) => ({
45
+ ...payload,
46
+ password: Redacted.make(payload.password),
47
+ ...(request === undefined ? {} : { request }),
48
+ });
49
+ export const passwordResetStartInput = (payload) => {
50
+ const { secret, ...input } = payload;
51
+ return {
52
+ ...input,
53
+ ...(secret === undefined ? {} : { secret: Redacted.make(secret) }),
54
+ };
55
+ };
56
+ export const passwordResetVerifyInput = (payload) => ({
57
+ challengeId: payload.challengeId,
58
+ secret: Redacted.make(payload.secret),
59
+ password: Redacted.make(payload.password),
60
+ });
61
+ export const passwordSetInput = (userId, payload) => ({
62
+ userId,
63
+ password: Redacted.make(payload.password),
64
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
65
+ });
66
+ export const passwordChangeInput = (userId, payload) => ({
67
+ userId,
68
+ currentPassword: Redacted.make(payload.currentPassword),
69
+ newPassword: Redacted.make(payload.newPassword),
70
+ });
71
+ export const emailVerificationStartInput = (payload) => {
72
+ const { secret, ...input } = payload;
73
+ return {
74
+ ...input,
75
+ ...(secret === undefined ? {} : { secret: Redacted.make(secret) }),
76
+ };
77
+ };
78
+ export const emailVerificationVerifyInput = (payload) => {
79
+ const { secret, ...input } = payload;
80
+ return {
81
+ ...input,
82
+ ...(secret === undefined ? {} : { secret: Redacted.make(secret) }),
83
+ };
84
+ };
85
+ export const emailOtpStartInput = (payload) => {
86
+ const { secret, ...input } = payload;
87
+ return {
88
+ ...input,
89
+ ...(secret === undefined ? {} : { secret: Redacted.make(secret) }),
90
+ };
91
+ };
92
+ export const emailOtpVerifyInput = (payload, trustedDeviceToken, request) => ({
93
+ challengeId: payload.challengeId,
94
+ secret: Redacted.make(payload.secret),
95
+ ...(trustedDeviceToken === undefined ? {} : { trustedDeviceToken }),
96
+ ...(request === undefined ? {} : { request }),
97
+ });
98
+ export const magicLinkStartInput = (payload) => {
99
+ const { secret, ...input } = payload;
100
+ return {
101
+ ...input,
102
+ ...(secret === undefined ? {} : { secret: Redacted.make(secret) }),
103
+ };
104
+ };
105
+ export const magicLinkVerifyInput = (payload, trustedDeviceToken, request) => ({
106
+ challengeId: payload.challengeId,
107
+ secret: Redacted.make(payload.secret),
108
+ ...(trustedDeviceToken === undefined ? {} : { trustedDeviceToken }),
109
+ ...(request === undefined ? {} : { request }),
110
+ });
111
+ export const oauthAuthorizationStartInput = (payload, provider, options = {}) => ({
112
+ provider,
113
+ ...(options.ttl === undefined ? {} : { ttl: options.ttl }),
114
+ ...(payload.redirectUri === undefined ? {} : { redirectUri: payload.redirectUri }),
115
+ ...(payload.scopes === undefined ? {} : { scopes: payload.scopes }),
116
+ ...(payload.authorizationParams === undefined
117
+ ? {}
118
+ : { authorizationParams: payload.authorizationParams }),
119
+ ...(payload.codeVerifier === undefined
120
+ ? {}
121
+ : { codeVerifier: Redacted.make(payload.codeVerifier) }),
122
+ ...(payload.includeNonce === undefined
123
+ ? {}
124
+ : { includeNonce: payload.includeNonce }),
125
+ ...(payload.nonce === undefined ? {} : { nonce: payload.nonce }),
126
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
127
+ });
128
+ export const oauthAuthorizationStartedHttpBody = (started) => ({
129
+ providerId: started.providerId,
130
+ authorizationUrl: started.authorizationUrl,
131
+ state: started.state,
132
+ challengeId: started.challengeId,
133
+ expiresAt: started.expiresAt,
134
+ codeChallenge: started.codeChallenge,
135
+ codeChallengeMethod: started.codeChallengeMethod,
136
+ ...(started.nonce === undefined ? {} : { nonce: started.nonce }),
137
+ redirectUri: started.redirectUri,
138
+ scopes: started.scopes,
139
+ });
140
+ const oauthVerifiedIdentityInput = (identity) => ({
141
+ providerId: identity.providerId,
142
+ providerAccountId: identity.providerAccountId,
143
+ ...(identity.email === undefined ? {} : { email: identity.email }),
144
+ ...(identity.emailVerified === undefined
145
+ ? {}
146
+ : { emailVerified: identity.emailVerified }),
147
+ ...(identity.metadata === undefined ? {} : { metadata: identity.metadata }),
148
+ });
149
+ export const oauthLinkConfirmationStartInput = (payload, options = {}) => Effect.gen(function* () {
150
+ if (payload.userId === undefined) {
151
+ return yield* oauthBadRequest("OAuth link confirmation is missing userId");
152
+ }
153
+ if (payload.identity === undefined) {
154
+ return yield* oauthBadRequest("OAuth link confirmation is missing identity");
155
+ }
156
+ return {
157
+ userId: payload.userId,
158
+ identity: oauthVerifiedIdentityInput(payload.identity),
159
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
160
+ ...(options.ttl === undefined ? {} : { ttl: options.ttl }),
161
+ ...(payload.secret === undefined
162
+ ? {}
163
+ : { secret: Redacted.make(payload.secret) }),
164
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
165
+ };
166
+ });
167
+ export const oauthLinkConfirmationInspectInput = (payload) => ({
168
+ challengeId: payload.challengeId,
169
+ ...(payload.secret === undefined ? {} : { secret: Redacted.make(payload.secret) }),
170
+ });
171
+ export const oauthLinkConfirmationConfirmInput = (payload, currentUserId) => ({
172
+ challengeId: payload.challengeId,
173
+ ...(payload.secret === undefined ? {} : { secret: Redacted.make(payload.secret) }),
174
+ ...(currentUserId === undefined ? {} : { currentUserId }),
175
+ ...(payload.expectedProviderId === undefined
176
+ ? {}
177
+ : { expectedProviderId: payload.expectedProviderId }),
178
+ ...(payload.expectedProviderAccountId === undefined
179
+ ? {}
180
+ : { expectedProviderAccountId: payload.expectedProviderAccountId }),
181
+ });
182
+ const oauthPublicVerifiedIdentityHttpBody = (identity) => ({
183
+ providerId: identity.providerId,
184
+ providerAccountId: identity.providerAccountId,
185
+ ...(identity.email === undefined ? {} : { email: identity.email }),
186
+ ...(identity.emailVerified === undefined
187
+ ? {}
188
+ : { emailVerified: identity.emailVerified }),
189
+ });
190
+ export const oauthLinkConfirmationStartedHttpBody = (started) => ({
191
+ challengeId: started.challengeId,
192
+ userId: started.userId,
193
+ identity: oauthPublicVerifiedIdentityHttpBody(started.identity),
194
+ reason: started.reason,
195
+ expiresAt: started.expiresAt,
196
+ });
197
+ export const oauthLinkConfirmationPendingHttpBody = (pending) => ({
198
+ challengeId: pending.challengeId,
199
+ userId: pending.userId,
200
+ identity: oauthPublicVerifiedIdentityHttpBody(pending.identity),
201
+ reason: pending.reason,
202
+ expiresAt: pending.expiresAt,
203
+ });
204
+ const oauthAuthorizationCallbackField = (fields, name) => {
205
+ const maybeSearchParams = fields;
206
+ const value = typeof maybeSearchParams.get === "function"
207
+ ? maybeSearchParams.get(name)
208
+ : fields[name];
209
+ const stringValue = Array.isArray(value) ? value[0] : value;
210
+ return typeof stringValue === "string" && stringValue.trim() !== ""
211
+ ? stringValue
212
+ : undefined;
213
+ };
214
+ const oauthAuthorizationCallbackPayload = (input, options) => Effect.gen(function* () {
215
+ const state = oauthAuthorizationCallbackField(input.fields, "state");
216
+ const code = oauthAuthorizationCallbackField(input.fields, "code");
217
+ const error = oauthAuthorizationCallbackField(input.fields, "error");
218
+ const errorDescription = oauthAuthorizationCallbackField(input.fields, "error_description");
219
+ const errorUri = oauthAuthorizationCallbackField(input.fields, "error_uri");
220
+ if (state === undefined) {
221
+ return yield* oauthBadRequest("OAuth callback is missing state");
222
+ }
223
+ const authorizationUser = options.includeAuthorizationUser
224
+ ? oauthAuthorizationCallbackField(input.fields, "user")
225
+ : undefined;
226
+ return {
227
+ providerId: input.providerId,
228
+ state,
229
+ ...(code === undefined ? {} : { code }),
230
+ ...(error === undefined ? {} : { error }),
231
+ ...(errorDescription === undefined ? {} : { errorDescription }),
232
+ ...(errorUri === undefined ? {} : { errorUri }),
233
+ ...(authorizationUser === undefined ? {} : { authorizationUser }),
234
+ };
235
+ });
236
+ export const oauthAuthorizationCallbackQueryPayload = (input) => oauthAuthorizationCallbackPayload(input, { includeAuthorizationUser: false });
237
+ export const oauthAuthorizationCallbackFormPostPayload = (input) => oauthAuthorizationCallbackPayload(input, { includeAuthorizationUser: true });
238
+ export const oauthAuthorizationCallbackInput = (payload, options) => Effect.gen(function* () {
239
+ if (payload.providerId !== options.provider.id) {
240
+ return yield* oauthBadRequest("OAuth callback provider mismatch");
241
+ }
242
+ if (payload.error !== undefined) {
243
+ return yield* oauthBadRequest("OAuth provider returned an error");
244
+ }
245
+ if (payload.code === undefined || payload.code.trim() === "") {
246
+ return yield* oauthBadRequest("OAuth callback is missing code");
247
+ }
248
+ return {
249
+ provider: options.provider,
250
+ state: payload.state,
251
+ code: payload.code,
252
+ codeVerifier: options.codeVerifier,
253
+ ...(options.redirectUri === undefined
254
+ ? {}
255
+ : { redirectUri: options.redirectUri }),
256
+ ...(options.clientAuthentication === undefined
257
+ ? {}
258
+ : { clientAuthentication: options.clientAuthentication }),
259
+ ...(options.tokenParams === undefined
260
+ ? {}
261
+ : { tokenParams: options.tokenParams }),
262
+ };
263
+ });
264
+ const oauthTokenTextDecoder = new TextDecoder();
265
+ const oauthTokenEndpointError = (reason, errorDescription) => new OAuthTokenEndpointError({
266
+ error: reason,
267
+ ...(errorDescription === undefined ? {} : { errorDescription }),
268
+ });
269
+ const oauthTokenRevocationEndpointError = (reason, errorDescription) => new OAuthTokenRevocationEndpointError({
270
+ error: reason,
271
+ ...(errorDescription === undefined ? {} : { errorDescription }),
272
+ });
273
+ const oauthTokenIntrospectionEndpointError = (reason, errorDescription) => new OAuthTokenIntrospectionEndpointError({
274
+ error: reason,
275
+ ...(errorDescription === undefined ? {} : { errorDescription }),
276
+ });
277
+ const oauthAuthorizationEndpointError = (reason, errorDescription) => new OAuthAuthorizationEndpointError({
278
+ error: reason,
279
+ ...(errorDescription === undefined ? {} : { errorDescription }),
280
+ });
281
+ const oauthAuthorizationRedirect = (redirectUri, params) => {
282
+ const url = new URL(redirectUri);
283
+ for (const [key, value] of Object.entries(params)) {
284
+ if (value !== undefined) {
285
+ url.searchParams.set(key, value);
286
+ }
287
+ }
288
+ return HttpServerResponse.empty({
289
+ status: 302,
290
+ headers: { location: url.toString() },
291
+ });
292
+ };
293
+ const oauthTokenGrantString = (value) => {
294
+ const trimmed = value?.trim();
295
+ return trimmed === undefined || trimmed === "" ? undefined : trimmed;
296
+ };
297
+ const formUrlDecodeComponent = (value) => {
298
+ try {
299
+ return new URLSearchParams(`value=${value}`).get("value") ?? value;
300
+ }
301
+ catch {
302
+ return value;
303
+ }
304
+ };
305
+ const decodeOAuthBasicAuthentication = (request, invalidClient) => {
306
+ const { authorization } = request.headers;
307
+ if (authorization === undefined || authorization.trim() === "") {
308
+ return Effect.succeed(Option.none());
309
+ }
310
+ if (!authorization.toLowerCase().startsWith("basic ")) {
311
+ return Effect.fail(invalidClient());
312
+ }
313
+ const encoded = authorization.slice("Basic ".length).trim();
314
+ if (encoded === "") {
315
+ return Effect.fail(invalidClient());
316
+ }
317
+ return Result.match(Encoding.decodeBase64(encoded), {
318
+ onFailure: () => Effect.fail(invalidClient()),
319
+ onSuccess: (bytes) => {
320
+ const decoded = oauthTokenTextDecoder.decode(bytes);
321
+ const separator = decoded.indexOf(":");
322
+ if (separator <= 0) {
323
+ return Effect.fail(invalidClient());
324
+ }
325
+ const clientId = oauthTokenGrantString(formUrlDecodeComponent(decoded.slice(0, separator)));
326
+ const clientSecret = formUrlDecodeComponent(decoded.slice(separator + 1));
327
+ if (clientId === undefined || clientSecret === "") {
328
+ return Effect.fail(invalidClient());
329
+ }
330
+ return Effect.succeed(Option.some({
331
+ clientId: makeOAuthClientId(clientId),
332
+ method: "client_secret_basic",
333
+ clientSecret: Redacted.make(clientSecret),
334
+ }));
335
+ },
336
+ });
337
+ };
338
+ const oauthTokenRequestBody = (request) => HttpServerRequest.schemaBodyUrlParams(OAuthTokenRequestBody).pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, request), Effect.mapError(() => oauthTokenEndpointError("invalid_request")));
339
+ const oauthTokenRevocationRequestBody = (request) => HttpServerRequest.schemaBodyUrlParams(OAuthTokenRevocationRequestBody).pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, request), Effect.mapError(() => oauthTokenRevocationEndpointError("invalid_request")));
340
+ const oauthTokenIntrospectionRequestBody = (request) => HttpServerRequest.schemaBodyUrlParams(OAuthTokenIntrospectionRequestBody).pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, request), Effect.mapError(() => oauthTokenIntrospectionEndpointError("invalid_request")));
341
+ const oauthPostClientAuthentication = (payload) => {
342
+ const clientSecret = oauthTokenGrantString(payload.client_secret);
343
+ const clientId = oauthTokenGrantString(payload.client_id);
344
+ if (clientSecret === undefined) {
345
+ return undefined;
346
+ }
347
+ return clientId === undefined
348
+ ? undefined
349
+ : {
350
+ clientId: makeOAuthClientId(clientId),
351
+ method: "client_secret_post",
352
+ clientSecret: Redacted.make(clientSecret),
353
+ };
354
+ };
355
+ const oauthClientEndpointAuthentication = (input) => Effect.gen(function* () {
356
+ const basicAuth = yield* decodeOAuthBasicAuthentication(input.request, input.invalidClient);
357
+ const postAuth = oauthPostClientAuthentication(input.payload);
358
+ if (Option.isSome(basicAuth) && input.payload.client_secret !== undefined) {
359
+ return yield* Effect.fail(input.invalidRequest());
360
+ }
361
+ if (input.payload.client_secret !== undefined && postAuth === undefined) {
362
+ return yield* Effect.fail(input.invalidRequest());
363
+ }
364
+ const authentication = Option.isSome(basicAuth) ? basicAuth.value : postAuth;
365
+ const payloadClientId = oauthTokenGrantString(input.payload.client_id);
366
+ if (authentication !== undefined &&
367
+ payloadClientId !== undefined &&
368
+ authentication.clientId !== payloadClientId) {
369
+ return yield* Effect.fail(input.invalidRequest());
370
+ }
371
+ const clientAuthenticated = authentication === undefined
372
+ ? false
373
+ : yield* Effect.gen(function* () {
374
+ if (input.authenticateClient === undefined) {
375
+ return yield* Effect.fail(input.invalidClient());
376
+ }
377
+ const authenticated = yield* input
378
+ .authenticateClient({
379
+ clientId: authentication.clientId,
380
+ method: authentication.method,
381
+ clientSecret: authentication.clientSecret,
382
+ request: input.request,
383
+ })
384
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to authenticate OAuth client")));
385
+ if (!authenticated) {
386
+ return yield* Effect.fail(input.invalidClient());
387
+ }
388
+ return true;
389
+ });
390
+ const clientId = authentication === undefined
391
+ ? payloadClientId === undefined
392
+ ? undefined
393
+ : makeOAuthClientId(payloadClientId)
394
+ : authentication.clientId;
395
+ return {
396
+ ...(clientId === undefined ? {} : { clientId }),
397
+ clientAuthenticated,
398
+ };
399
+ });
400
+ const oauthTokenResponseHttpBody = (tokens) => ({
401
+ access_token: Redacted.value(tokens.accessToken),
402
+ token_type: tokens.tokenType,
403
+ ...(tokens.expiresIn === undefined ? {} : { expires_in: tokens.expiresIn }),
404
+ ...(tokens.refreshToken === undefined
405
+ ? {}
406
+ : { refresh_token: Redacted.value(tokens.refreshToken) }),
407
+ ...(tokens.idToken === undefined
408
+ ? {}
409
+ : { id_token: Redacted.value(tokens.idToken) }),
410
+ ...(tokens.scopes === undefined ? {} : { scope: tokens.scopes.join(" ") }),
411
+ ...(tokens.extra === undefined ? {} : { extra: tokens.extra }),
412
+ });
413
+ const oauthUnixMillisToSeconds = (value) => Math.floor(Number(value) / 1000);
414
+ const oauthTokenIntrospectionResponseHttpBody = (introspection) => {
415
+ if (!introspection.active) {
416
+ return { active: false };
417
+ }
418
+ return {
419
+ active: true,
420
+ ...(introspection.scopes === undefined
421
+ ? {}
422
+ : { scope: introspection.scopes.join(" ") }),
423
+ ...(introspection.clientId === undefined
424
+ ? {}
425
+ : { client_id: String(introspection.clientId) }),
426
+ ...(introspection.username === undefined
427
+ ? {}
428
+ : { username: introspection.username }),
429
+ ...(introspection.tokenType === undefined
430
+ ? {}
431
+ : { token_type: introspection.tokenType }),
432
+ ...(introspection.expiresAt === undefined
433
+ ? {}
434
+ : { exp: oauthUnixMillisToSeconds(introspection.expiresAt) }),
435
+ ...(introspection.issuedAt === undefined
436
+ ? {}
437
+ : { iat: oauthUnixMillisToSeconds(introspection.issuedAt) }),
438
+ ...(introspection.notBefore === undefined
439
+ ? {}
440
+ : { nbf: oauthUnixMillisToSeconds(introspection.notBefore) }),
441
+ ...(introspection.subject === undefined ? {} : { sub: introspection.subject }),
442
+ ...(introspection.audience === undefined
443
+ ? {}
444
+ : {
445
+ aud: Array.isArray(introspection.audience)
446
+ ? [...introspection.audience]
447
+ : introspection.audience,
448
+ }),
449
+ ...(introspection.issuer === undefined ? {} : { iss: introspection.issuer }),
450
+ ...(introspection.jwtId === undefined ? {} : { jti: introspection.jwtId }),
451
+ ...(introspection.extra === undefined ? {} : { extra: introspection.extra }),
452
+ };
453
+ };
454
+ const oauthRefreshTokenResponse = (input) => Effect.gen(function* () {
455
+ if (input.dependencies.refreshTokenGrant === undefined) {
456
+ return yield* oauthTokenEndpointError("unsupported_grant_type");
457
+ }
458
+ const refreshToken = oauthTokenGrantString(input.payload.refresh_token);
459
+ const scope = oauthTokenGrantString(input.payload.scope);
460
+ const result = yield* input.dependencies.refreshTokenGrant
461
+ .exchange({
462
+ grantType: input.payload.grant_type,
463
+ ...(refreshToken === undefined
464
+ ? {}
465
+ : { refreshToken: Redacted.make(OAuthRefreshToken(refreshToken)) }),
466
+ ...(input.clientId === undefined ? {} : { clientId: input.clientId }),
467
+ ...(scope === undefined ? {} : { scopes: scope }),
468
+ clientAuthenticated: input.clientAuthenticated,
469
+ })
470
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to exchange OAuth token")));
471
+ if (!result.valid) {
472
+ return yield* oauthTokenEndpointError(result.reason);
473
+ }
474
+ return oauthTokenResponseHttpBody(result.tokens);
475
+ });
476
+ const oauthClientCredentialsTokenResponse = (input) => Effect.gen(function* () {
477
+ if (input.dependencies.clientCredentialsGrant === undefined) {
478
+ return yield* oauthTokenEndpointError("unsupported_grant_type");
479
+ }
480
+ const scope = oauthTokenGrantString(input.payload.scope);
481
+ const result = yield* input.dependencies.clientCredentialsGrant
482
+ .exchange({
483
+ grantType: input.payload.grant_type,
484
+ ...(input.clientId === undefined ? {} : { clientId: input.clientId }),
485
+ ...(scope === undefined ? {} : { scopes: scope }),
486
+ clientAuthenticated: input.clientAuthenticated,
487
+ })
488
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to exchange OAuth token")));
489
+ if (!result.valid) {
490
+ return yield* oauthTokenEndpointError(result.reason);
491
+ }
492
+ return oauthTokenResponseHttpBody(result.tokens);
493
+ });
494
+ const oauthAuthorizationCodeTokenResponse = (input) => Effect.gen(function* () {
495
+ const code = oauthTokenGrantString(input.payload.code);
496
+ const codeVerifier = oauthTokenGrantString(input.payload.code_verifier);
497
+ const redirectUri = oauthTokenGrantString(input.payload.redirect_uri);
498
+ const result = yield* input.dependencies.tokenGrant
499
+ .exchange({
500
+ grantType: input.payload.grant_type,
501
+ ...(code === undefined
502
+ ? {}
503
+ : { code: Redacted.make(OAuthAuthorizationCode(code)) }),
504
+ ...(input.clientId === undefined ? {} : { clientId: input.clientId }),
505
+ ...(redirectUri === undefined ? {} : { redirectUri }),
506
+ ...(codeVerifier === undefined
507
+ ? {}
508
+ : { codeVerifier: Redacted.make(makeOAuthCodeVerifier(codeVerifier)) }),
509
+ clientAuthenticated: input.clientAuthenticated,
510
+ })
511
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to exchange OAuth token")));
512
+ if (!result.valid) {
513
+ return yield* oauthTokenEndpointError(result.reason);
514
+ }
515
+ return oauthTokenResponseHttpBody(result.tokens);
516
+ });
517
+ const oauthLinkedAccountHttpBody = (account) => ({
518
+ accountId: account.id,
519
+ providerId: account.providerId,
520
+ providerAccountId: account.providerAccountId,
521
+ });
522
+ export const oauthLinkConfirmationConfirmedHttpBody = (confirmed, options = {}) => ({
523
+ challengeId: confirmed.challengeId,
524
+ userId: confirmed.userId,
525
+ identity: oauthPublicVerifiedIdentityHttpBody(confirmed.identity),
526
+ reason: confirmed.reason,
527
+ ...(confirmed.existingAccount === undefined
528
+ ? {}
529
+ : { existingAccount: oauthLinkedAccountHttpBody(confirmed.existingAccount) }),
530
+ linked: options.linked === true || confirmed.existingAccount !== undefined,
531
+ });
532
+ export const oauthAccountUnlinkResolutionHttpBody = (resolution, options = {}) => {
533
+ switch (resolution.type) {
534
+ case "allow": {
535
+ return {
536
+ type: resolution.type,
537
+ reason: resolution.reason,
538
+ account: oauthLinkedAccountHttpBody(resolution.account),
539
+ remainingAccounts: resolution.remainingAccounts.map(oauthLinkedAccountHttpBody),
540
+ unlinked: options.unlinked === true,
541
+ };
542
+ }
543
+ case "requires-step-up": {
544
+ return {
545
+ type: resolution.type,
546
+ reason: resolution.reason,
547
+ account: oauthLinkedAccountHttpBody(resolution.account),
548
+ remainingAccounts: resolution.remainingAccounts.map(oauthLinkedAccountHttpBody),
549
+ };
550
+ }
551
+ case "deny-last-account": {
552
+ return {
553
+ type: resolution.type,
554
+ reason: resolution.reason,
555
+ account: oauthLinkedAccountHttpBody(resolution.account),
556
+ };
557
+ }
558
+ case "deny-not-owner": {
559
+ return {
560
+ type: resolution.type,
561
+ reason: resolution.reason,
562
+ providerId: resolution.account.providerId,
563
+ providerAccountId: resolution.account.providerAccountId,
564
+ };
565
+ }
566
+ case "deny-not-found": {
567
+ return {
568
+ type: resolution.type,
569
+ reason: resolution.reason,
570
+ providerId: resolution.providerId,
571
+ providerAccountId: resolution.providerAccountId,
572
+ };
573
+ }
574
+ }
575
+ };
576
+ export const passkeyRegistrationStartInput = (payload, options) => ({
577
+ relyingParty: options.relyingParty,
578
+ userId: payload.userId,
579
+ userName: payload.userName,
580
+ userDisplayName: payload.userDisplayName,
581
+ ...(options.timeout === undefined ? {} : { timeout: options.timeout }),
582
+ ...(options.pubKeyCredParams === undefined
583
+ ? {}
584
+ : { pubKeyCredParams: options.pubKeyCredParams }),
585
+ ...(options.authenticatorSelection === undefined
586
+ ? {}
587
+ : { authenticatorSelection: options.authenticatorSelection }),
588
+ ...(options.attestation === undefined ? {} : { attestation: options.attestation }),
589
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
590
+ });
591
+ export const passkeyAuthenticationStartInput = (payload, options) => ({
592
+ relyingPartyId: options.relyingPartyId,
593
+ ...(payload.userId === undefined ? {} : { userId: payload.userId }),
594
+ ...(options.timeout === undefined ? {} : { timeout: options.timeout }),
595
+ ...(options.userVerification === undefined
596
+ ? {}
597
+ : { userVerification: options.userVerification }),
598
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
599
+ });
600
+ export const passkeyMfaStartInput = (userId, payload, options) => ({
601
+ relyingPartyId: options.relyingPartyId,
602
+ userId,
603
+ ...(options.timeout === undefined ? {} : { timeout: options.timeout }),
604
+ userVerification: options.userVerification ?? "required",
605
+ metadata: {
606
+ ...payload.metadata,
607
+ flowId: payload.flowId,
608
+ },
609
+ });
610
+ export const passkeyRegistrationFinishInput = (payload, options) => ({
611
+ challengeId: payload.challengeId,
612
+ userId: payload.userId,
613
+ response: payload.credential,
614
+ relyingPartyId: options.relyingPartyId,
615
+ expectedOrigin: options.expectedOrigin,
616
+ ...(options.requireUserVerification === undefined
617
+ ? {}
618
+ : { requireUserVerification: options.requireUserVerification }),
619
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
620
+ });
621
+ export const passkeyAuthenticationFinishInput = (payload, options) => ({
622
+ challengeId: payload.challengeId,
623
+ response: payload.credential,
624
+ ...(payload.userId === undefined ? {} : { userId: payload.userId }),
625
+ relyingPartyId: options.relyingPartyId,
626
+ expectedOrigin: options.expectedOrigin,
627
+ ...(options.requireUserVerification === undefined
628
+ ? {}
629
+ : { requireUserVerification: options.requireUserVerification }),
630
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
631
+ });
632
+ export const passkeyMfaVerifyInput = (payload, options) => ({
633
+ challengeId: payload.challengeId,
634
+ response: payload.credential,
635
+ ...(payload.userId === undefined ? {} : { userId: payload.userId }),
636
+ relyingPartyId: options.relyingPartyId,
637
+ expectedOrigin: options.expectedOrigin,
638
+ ...(options.requireUserVerification === undefined
639
+ ? {}
640
+ : { requireUserVerification: options.requireUserVerification }),
641
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
642
+ });
643
+ export const passkeyCredentialRevokeInput = (userId, payload) => ({
644
+ userId,
645
+ credentialId: PasskeyCredentialId(payload.credentialId),
646
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
647
+ });
648
+ const passkeyCredentialInfoHttpBody = (credential) => ({
649
+ credentialId: credential.credentialId,
650
+ ...(credential.transports === undefined
651
+ ? {}
652
+ : { transports: credential.transports }),
653
+ ...(credential.backedUp === undefined ? {} : { backedUp: credential.backedUp }),
654
+ createdAt: credential.createdAt,
655
+ ...(credential.lastUsedAt === undefined
656
+ ? {}
657
+ : { lastUsedAt: credential.lastUsedAt }),
658
+ ...(credential.revokedAt === undefined
659
+ ? {}
660
+ : { revokedAt: credential.revokedAt }),
661
+ ...(credential.metadata === undefined ? {} : { metadata: credential.metadata }),
662
+ });
663
+ export const totpEnrollmentStartInput = (userId, payload, options) => ({
664
+ userId,
665
+ issuer: options.issuer,
666
+ accountName: payload.accountName,
667
+ ...(options.secretBytes === undefined ? {} : { secretBytes: options.secretBytes }),
668
+ ...(options.algorithm === undefined ? {} : { algorithm: options.algorithm }),
669
+ ...(options.digits === undefined ? {} : { digits: options.digits }),
670
+ ...(options.period === undefined ? {} : { period: options.period }),
671
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
672
+ });
673
+ export const totpEnrollmentConfirmInput = (userId, payload, options = {}) => ({
674
+ userId,
675
+ factorId: payload.factorId,
676
+ code: Redacted.make(payload.code),
677
+ ...(options.window === undefined ? {} : { window: options.window }),
678
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
679
+ });
680
+ export const totpVerifyInput = (userId, payload, options = {}) => ({
681
+ userId,
682
+ code: Redacted.make(payload.code),
683
+ ...(options.window === undefined ? {} : { window: options.window }),
684
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
685
+ });
686
+ export const totpFactorRevokeInput = (userId, payload) => ({
687
+ userId,
688
+ factorId: payload.factorId,
689
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
690
+ });
691
+ const totpFactorInfoHttpBody = (factor) => ({
692
+ factorId: factor.id,
693
+ algorithm: factor.algorithm,
694
+ digits: factor.digits,
695
+ period: factor.period,
696
+ createdAt: factor.createdAt,
697
+ ...(factor.confirmedAt === undefined ? {} : { confirmedAt: factor.confirmedAt }),
698
+ ...(factor.lastUsedAt === undefined ? {} : { lastUsedAt: factor.lastUsedAt }),
699
+ ...(factor.revokedAt === undefined ? {} : { revokedAt: factor.revokedAt }),
700
+ ...(factor.metadata === undefined ? {} : { metadata: factor.metadata }),
701
+ });
702
+ const totpEnrollmentStartedHttpBody = (started) => ({
703
+ factor: totpFactorInfoHttpBody(started.factor),
704
+ secret: Redacted.value(started.secret),
705
+ uri: Redacted.value(started.uri),
706
+ });
707
+ const totpVerifyResultHttpBody = (result) => ({
708
+ valid: result.valid,
709
+ ...(result.factor === undefined
710
+ ? {}
711
+ : { factor: totpFactorInfoHttpBody(result.factor) }),
712
+ ...(result.delta === undefined ? {} : { delta: result.delta }),
713
+ });
714
+ export const recoveryCodeGenerateInput = (userId, payload, options = {}) => ({
715
+ userId,
716
+ ...(options.count === undefined ? {} : { count: options.count }),
717
+ ...(options.length === undefined ? {} : { length: options.length }),
718
+ ...(options.groupSize === undefined ? {} : { groupSize: options.groupSize }),
719
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
720
+ });
721
+ export const recoveryCodeVerifyInput = (userId, payload) => ({
722
+ userId,
723
+ code: Redacted.make(payload.code),
724
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
725
+ });
726
+ export const recoveryCodeRevokeInput = (userId, payload) => ({
727
+ userId,
728
+ codeId: payload.codeId,
729
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
730
+ });
731
+ const recoveryCodeInfoHttpBody = (code) => ({
732
+ codeId: code.id,
733
+ createdAt: code.createdAt,
734
+ ...(code.usedAt === undefined ? {} : { usedAt: code.usedAt }),
735
+ ...(code.revokedAt === undefined ? {} : { revokedAt: code.revokedAt }),
736
+ ...(code.metadata === undefined ? {} : { metadata: code.metadata }),
737
+ });
738
+ const recoveryCodesGeneratedHttpBody = (generated) => ({
739
+ codes: generated.codes.map(Redacted.value),
740
+ records: generated.records.map(recoveryCodeInfoHttpBody),
741
+ });
742
+ const recoveryCodeVerifyResultHttpBody = (result) => ({
743
+ valid: result.valid,
744
+ ...(result.code === undefined
745
+ ? {}
746
+ : { code: recoveryCodeInfoHttpBody(result.code) }),
747
+ });
748
+ export const apiKeyCreateInput = (userId, payload) => ({
749
+ userId,
750
+ ...(payload.scopes === undefined ? {} : { scopes: payload.scopes }),
751
+ ...(payload.expiresAt === undefined ? {} : { expiresAt: payload.expiresAt }),
752
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
753
+ });
754
+ export const apiKeyRevokeInput = (userId, payload) => ({
755
+ userId,
756
+ keyId: ApiKeyId(payload.keyId),
757
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
758
+ });
759
+ const apiKeyInfoHttpBody = (key) => ({
760
+ keyId: key.id,
761
+ prefix: key.prefix,
762
+ scopes: key.scopes,
763
+ createdAt: key.createdAt,
764
+ ...(key.expiresAt === undefined ? {} : { expiresAt: key.expiresAt }),
765
+ ...(key.lastUsedAt === undefined ? {} : { lastUsedAt: key.lastUsedAt }),
766
+ ...(key.revokedAt === undefined ? {} : { revokedAt: key.revokedAt }),
767
+ ...(key.metadata === undefined ? {} : { metadata: key.metadata }),
768
+ });
769
+ const apiKeyCreatedHttpBody = (created) => ({
770
+ secret: Redacted.value(created.secret),
771
+ key: apiKeyInfoHttpBody(created.key),
772
+ });
773
+ export const refreshTokenRefreshInput = (payload, now, expiresAt) => ({
774
+ token: Redacted.make(payload.refreshToken),
775
+ now,
776
+ expiresAt,
777
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
778
+ });
779
+ const refreshTokenInfoHttpBody = (refreshToken) => ({
780
+ tokenId: refreshToken.id,
781
+ familyId: refreshToken.familyId,
782
+ createdAt: refreshToken.createdAt,
783
+ expiresAt: refreshToken.expiresAt,
784
+ ...(refreshToken.lastUsedAt === undefined
785
+ ? {}
786
+ : { lastUsedAt: refreshToken.lastUsedAt }),
787
+ ...(refreshToken.rotatedAt === undefined
788
+ ? {}
789
+ : { rotatedAt: refreshToken.rotatedAt }),
790
+ ...(refreshToken.replacedById === undefined
791
+ ? {}
792
+ : { replacedById: refreshToken.replacedById }),
793
+ ...(refreshToken.revokedAt === undefined
794
+ ? {}
795
+ : { revokedAt: refreshToken.revokedAt }),
796
+ ...(refreshToken.reuseDetectedAt === undefined
797
+ ? {}
798
+ : { reuseDetectedAt: refreshToken.reuseDetectedAt }),
799
+ ...(refreshToken.metadata === undefined ? {} : { metadata: refreshToken.metadata }),
800
+ });
801
+ const issuedJwtExpiresAt = (issued) => typeof issued.claims.exp === "number"
802
+ ? (issued.claims.exp * 1000)
803
+ : undefined;
804
+ const refreshTokenRefreshedHttpBody = (input) => ({
805
+ accessToken: Redacted.value(input.accessToken.token),
806
+ ...(issuedJwtExpiresAt(input.accessToken) === undefined
807
+ ? {}
808
+ : { accessTokenExpiresAt: issuedJwtExpiresAt(input.accessToken) }),
809
+ refreshToken: input.refreshToken,
810
+ refreshTokenRecord: refreshTokenInfoHttpBody(input.refreshTokenRecord),
811
+ });
812
+ export const jwtIntrospectInput = (payload, options = {}) => ({
813
+ token: Redacted.make(payload.token),
814
+ ...(options.issuer === undefined ? {} : { issuer: options.issuer }),
815
+ ...(options.audience === undefined ? {} : { audience: options.audience }),
816
+ ...(options.clockTolerance === undefined
817
+ ? {}
818
+ : { clockTolerance: options.clockTolerance }),
819
+ });
820
+ export const jwtRevokeInput = (payload) => ({
821
+ jwtId: payload.jwtId,
822
+ ...(payload.expiresAt === undefined ? {} : { expiresAt: payload.expiresAt }),
823
+ ...(payload.reason === undefined ? {} : { reason: payload.reason }),
824
+ });
825
+ const jwtKeyInfoHttpBody = (result) => ({
826
+ keyId: result.key.id,
827
+ alg: result.key.alg,
828
+ status: result.key.status,
829
+ ...(result.key.createdAt === undefined ? {} : { createdAt: result.key.createdAt }),
830
+ ...(result.key.expiresAt === undefined ? {} : { expiresAt: result.key.expiresAt }),
831
+ ...(result.key.metadata === undefined ? {} : { metadata: result.key.metadata }),
832
+ });
833
+ const jwtIntrospectionHttpBody = (result) => result.active
834
+ ? {
835
+ active: true,
836
+ header: result.header,
837
+ claims: result.claims,
838
+ key: jwtKeyInfoHttpBody(result),
839
+ ...(result.jwtId === undefined ? {} : { jwtId: result.jwtId }),
840
+ ...(result.expiresAt === undefined ? {} : { expiresAt: result.expiresAt }),
841
+ revoked: false,
842
+ }
843
+ : {
844
+ active: false,
845
+ reason: result.reason,
846
+ ...(result.jwtId === undefined ? {} : { jwtId: result.jwtId }),
847
+ ...(result.expiresAt === undefined ? {} : { expiresAt: result.expiresAt }),
848
+ ...(result.revokedAt === undefined ? {} : { revokedAt: result.revokedAt }),
849
+ ...(result.revokedReason === undefined
850
+ ? {}
851
+ : { revokedReason: result.revokedReason }),
852
+ };
853
+ export const jwtJwksHttpBody = (document) => ({
854
+ keys: document.keys,
855
+ });
856
+ export const totpMfaVerifyInput = (payload, options = {}) => ({
857
+ userId: payload.userId,
858
+ code: Redacted.make(payload.code),
859
+ ...(options.window === undefined ? {} : { window: options.window }),
860
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
861
+ });
862
+ export const totpMfaVerifyForFlowInput = (userId, payload, options = {}) => ({
863
+ userId,
864
+ code: Redacted.make(payload.code),
865
+ ...(options.window === undefined ? {} : { window: options.window }),
866
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
867
+ });
868
+ export const recoveryCodeMfaVerifyInput = (payload) => ({
869
+ userId: payload.userId,
870
+ code: Redacted.make(payload.code),
871
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
872
+ });
873
+ export const recoveryCodeMfaVerifyForFlowInput = (userId, payload) => ({
874
+ userId,
875
+ code: Redacted.make(payload.code),
876
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
877
+ });
878
+ export const stepUpTotpVerifyInput = (userId, payload, options = {}) => ({
879
+ userId,
880
+ code: Redacted.make(payload.code),
881
+ ...(options.window === undefined ? {} : { window: options.window }),
882
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
883
+ });
884
+ export const stepUpRecoveryCodeVerifyInput = (userId, payload) => ({
885
+ userId,
886
+ code: Redacted.make(payload.code),
887
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
888
+ });
889
+ export const stepUpPasskeyStartInput = (userId, payload, options) => ({
890
+ relyingPartyId: options.relyingPartyId,
891
+ userId,
892
+ ...(options.timeout === undefined ? {} : { timeout: options.timeout }),
893
+ userVerification: options.userVerification ?? "required",
894
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
895
+ });
896
+ export const stepUpPasskeyVerifyInput = (userId, payload, options) => ({
897
+ challengeId: payload.challengeId,
898
+ response: payload.credential,
899
+ userId,
900
+ relyingPartyId: options.relyingPartyId,
901
+ expectedOrigin: options.expectedOrigin,
902
+ ...(options.requireUserVerification === undefined
903
+ ? {}
904
+ : { requireUserVerification: options.requireUserVerification }),
905
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
906
+ });
907
+ export const loginApprovalApproveInput = (payload) => ({
908
+ flowId: payload.flowId,
909
+ approval: {
910
+ challengeId: payload.approvalChallengeId,
911
+ ...(payload.secret === undefined
912
+ ? {}
913
+ : { secret: Redacted.make(payload.secret) }),
914
+ },
915
+ rememberDevice: payload.rememberDevice ?? false,
916
+ });
917
+ export const loginApprovalStatusInput = (payload) => ({
918
+ flowId: payload.flowId,
919
+ approvalChallengeId: payload.approvalChallengeId,
920
+ });
921
+ export const loginApprovalFinalizeInput = (payload) => ({
922
+ flowId: payload.flowId,
923
+ approvalChallengeId: payload.approvalChallengeId,
924
+ rememberDevice: payload.rememberDevice ?? false,
925
+ });
926
+ export const loginNotificationReportInput = (payload) => ({
927
+ challengeId: payload.challengeId,
928
+ secret: Redacted.make(payload.secret),
929
+ });
930
+ const webRequestFromHeaders = (headers) => new Request("http://localhost", { headers });
931
+ const firstHeaderValue = (value) => {
932
+ const first = value?.split(",", 1)[0]?.trim();
933
+ return first === "" ? undefined : first;
934
+ };
935
+ const headerNumber = (value) => {
936
+ const parsed = Number(firstHeaderValue(value));
937
+ return Number.isFinite(parsed) ? parsed : undefined;
938
+ };
939
+ const authRequestMetadataOptions = Effect.gen(function* () {
940
+ const config = yield* Effect.serviceOption(AuthHttpApiConfig);
941
+ return Option.isSome(config) ? (config.value.requestMetadata ?? {}) : {};
942
+ });
943
+ const loginRequestContextFromRequest = (request, options) => {
944
+ if (request === undefined) {
945
+ return undefined;
946
+ }
947
+ const metadata = makeAuthRequestMetadata(request, options);
948
+ const trustProxyHeaders = options.trustProxyHeaders ?? false;
949
+ const { headers } = request;
950
+ const country = trustProxyHeaders
951
+ ? firstHeaderValue(headers["cf-ipcountry"])
952
+ : undefined;
953
+ const region = trustProxyHeaders
954
+ ? firstHeaderValue(headers["cf-region"])
955
+ : undefined;
956
+ const city = trustProxyHeaders
957
+ ? firstHeaderValue(headers["cf-ipcity"])
958
+ : undefined;
959
+ const latitude = trustProxyHeaders
960
+ ? headerNumber(headers["cf-iplatitude"])
961
+ : undefined;
962
+ const longitude = trustProxyHeaders
963
+ ? headerNumber(headers["cf-iplongitude"])
964
+ : undefined;
965
+ const context = {
966
+ ...(metadata.ipAddress === undefined
967
+ ? {}
968
+ : { ip: String(metadata.ipAddress) }),
969
+ ...(metadata.userAgent === undefined
970
+ ? {}
971
+ : { userAgent: metadata.userAgent }),
972
+ ...(country === undefined ? {} : { country }),
973
+ ...(region === undefined ? {} : { region }),
974
+ ...(city === undefined ? {} : { city }),
975
+ ...(latitude === undefined ? {} : { latitude }),
976
+ ...(longitude === undefined ? {} : { longitude }),
977
+ };
978
+ return Object.keys(context).length === 0 ? undefined : context;
979
+ };
980
+ const trustedDeviceTokenFromRequest = (trustedDeviceCookie, request) => trustedDeviceCookie === undefined || request === undefined
981
+ ? Effect.succeed(Option.none())
982
+ : trustedDeviceCookie.read(new Request("http://localhost", { headers: request.headers }));
983
+ const metadataString = (metadata, key) => {
984
+ const value = metadata?.[key];
985
+ return typeof value === "string" && value.length > 0 ? value : undefined;
986
+ };
987
+ const emailVerifiedClaims = (claims) => {
988
+ const requirements = claims?.requirements?.filter((requirement) => requirement !== "email_verification");
989
+ return {
990
+ ...claims,
991
+ emailVerified: true,
992
+ ...(requirements === undefined ? {} : { requirements }),
993
+ };
994
+ };
995
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
996
+ const metadataNumber = (metadata, key) => {
997
+ const value = metadata?.[key];
998
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
999
+ };
1000
+ const sessionRequestMetadata = (metadata) => {
1001
+ const value = metadata?.[sessionRequestMetadataKey];
1002
+ return isRecord(value) ? value : undefined;
1003
+ };
1004
+ const activeSessionBody = (session, currentSessionId) => {
1005
+ const request = sessionRequestMetadata(session.metadata);
1006
+ const ip = metadataString(request, "ip");
1007
+ const userAgent = metadataString(request, "userAgent");
1008
+ const country = metadataString(request, "country");
1009
+ const region = metadataString(request, "region");
1010
+ const city = metadataString(request, "city");
1011
+ const latitude = metadataNumber(request, "latitude");
1012
+ const longitude = metadataNumber(request, "longitude");
1013
+ return {
1014
+ sessionId: session.sessionId,
1015
+ userId: session.userId,
1016
+ createdAt: session.createdAt,
1017
+ authTime: session.authTime,
1018
+ ...(session.lastSeenAt === undefined
1019
+ ? {}
1020
+ : { lastSeenAt: session.lastSeenAt }),
1021
+ expiresAt: session.expiresAt,
1022
+ aal: session.aal,
1023
+ amr: session.amr,
1024
+ ...(session.mfaVerifiedAt === undefined
1025
+ ? {}
1026
+ : { mfaVerifiedAt: session.mfaVerifiedAt }),
1027
+ current: session.sessionId === currentSessionId,
1028
+ ...(session.claims === undefined ? {} : { claims: session.claims }),
1029
+ ...(ip === undefined ? {} : { ip }),
1030
+ ...(userAgent === undefined ? {} : { userAgent }),
1031
+ ...(country === undefined ? {} : { country }),
1032
+ ...(region === undefined ? {} : { region }),
1033
+ ...(city === undefined ? {} : { city }),
1034
+ ...(latitude === undefined ? {} : { latitude }),
1035
+ ...(longitude === undefined ? {} : { longitude }),
1036
+ ...(session.metadata === undefined ? {} : { metadata: session.metadata }),
1037
+ };
1038
+ };
1039
+ export const adminSessionHttpBody = (session) => {
1040
+ const request = sessionRequestMetadata(session.metadata);
1041
+ const ip = metadataString(request, "ip");
1042
+ const userAgent = metadataString(request, "userAgent");
1043
+ const country = metadataString(request, "country");
1044
+ const region = metadataString(request, "region");
1045
+ const city = metadataString(request, "city");
1046
+ const latitude = metadataNumber(request, "latitude");
1047
+ const longitude = metadataNumber(request, "longitude");
1048
+ return {
1049
+ sessionId: session.sessionId,
1050
+ userId: session.userId,
1051
+ createdAt: session.createdAt,
1052
+ authTime: session.authTime,
1053
+ ...(session.lastSeenAt === undefined
1054
+ ? {}
1055
+ : { lastSeenAt: session.lastSeenAt }),
1056
+ expiresAt: session.expiresAt,
1057
+ aal: session.aal,
1058
+ amr: session.amr,
1059
+ ...(session.mfaVerifiedAt === undefined
1060
+ ? {}
1061
+ : { mfaVerifiedAt: session.mfaVerifiedAt }),
1062
+ ...(ip === undefined ? {} : { ip }),
1063
+ ...(userAgent === undefined ? {} : { userAgent }),
1064
+ ...(country === undefined ? {} : { country }),
1065
+ ...(region === undefined ? {} : { region }),
1066
+ ...(city === undefined ? {} : { city }),
1067
+ ...(latitude === undefined ? {} : { latitude }),
1068
+ ...(longitude === undefined ? {} : { longitude }),
1069
+ };
1070
+ };
1071
+ export const stepUpAuthenticatedHttpBody = (session) => {
1072
+ const body = {
1073
+ type: "authenticated",
1074
+ expiresAt: Number(session.expiresAt),
1075
+ aal: session.aal,
1076
+ amr: session.amr,
1077
+ ...(session.mfaVerifiedAt === undefined
1078
+ ? {}
1079
+ : { mfaVerifiedAt: session.mfaVerifiedAt }),
1080
+ };
1081
+ return session.claims === undefined ? body : { ...body, claims: session.claims };
1082
+ };
1083
+ const readOptionalSession = (dependencies, request) => Effect.gen(function* () {
1084
+ const tokenOption = yield* dependencies.sessionCookie
1085
+ .read(webRequestFromHeaders(request.headers))
1086
+ .pipe(Effect.catchTag("SessionValidateError", (error) => error.cause === undefined
1087
+ ? Effect.succeed(Option.none())
1088
+ : Effect.fail(new AuthInternalError({
1089
+ code: "internal_error",
1090
+ message: "Failed to validate session",
1091
+ }))));
1092
+ if (Option.isNone(tokenOption)) {
1093
+ return Option.none();
1094
+ }
1095
+ return yield* dependencies.sessions.validate(tokenOption.value).pipe(Effect.map(Option.some), Effect.catchTag("SessionValidateError", (error) => error.cause === undefined
1096
+ ? Effect.succeed(Option.none())
1097
+ : Effect.fail(new AuthInternalError({
1098
+ code: "internal_error",
1099
+ message: "Failed to validate session",
1100
+ }))));
1101
+ });
1102
+ const readRequiredSession = (dependencies, request) => readOptionalSession(dependencies, request).pipe(Effect.flatMap((sessionOption) => Option.isSome(sessionOption)
1103
+ ? Effect.succeed(sessionOption.value)
1104
+ : Effect.fail(new AuthUnauthenticatedError({
1105
+ code: "unauthenticated",
1106
+ message: "Unauthenticated",
1107
+ }))));
1108
+ const upgradeVerifiedEmailSession = (dependencies, request, verified) => Effect.gen(function* () {
1109
+ const sessionOption = yield* readOptionalSession(dependencies, request);
1110
+ if (Option.isNone(sessionOption)) {
1111
+ return;
1112
+ }
1113
+ const session = sessionOption.value.currentSession;
1114
+ if (session.userId !== verified.user.id) {
1115
+ return;
1116
+ }
1117
+ yield* dependencies.sessions
1118
+ .updateClaims({
1119
+ sessionId: session.sessionId,
1120
+ claims: emailVerifiedClaims(session.claims),
1121
+ reason: "email_verification",
1122
+ })
1123
+ .pipe(Effect.catchTag("SessionUpdateClaimsError", (error) => error.cause === undefined
1124
+ ? Effect.void
1125
+ : Effect.fail(new AuthInternalError({
1126
+ code: "internal_error",
1127
+ message: "Failed to update session claims",
1128
+ }))));
1129
+ });
1130
+ const startRequiredEmailVerification = (dependencies, result) => Effect.gen(function* () {
1131
+ if (dependencies.emailVerificationFlow === undefined ||
1132
+ !canStartRequiredEmailVerification(result)) {
1133
+ return result;
1134
+ }
1135
+ const input = {
1136
+ userId: result.userId,
1137
+ email: result.email,
1138
+ };
1139
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1140
+ yield* catchAuthApiRateLimit(authApiRateLimit.emailVerificationStart(input), "Failed to start email verification");
1141
+ yield* dependencies.emailVerificationFlow
1142
+ .start(input)
1143
+ .pipe(Effect.catchTag("EmailVerificationFlowStartError", () => Effect.fail(passwordInternalError("Failed to start email verification"))));
1144
+ return result;
1145
+ });
1146
+ const rateLimited = (retryAfter) => new AuthRateLimitedError({
1147
+ code: "rate_limited",
1148
+ message: "Too many authentication attempts",
1149
+ retryAfter,
1150
+ });
1151
+ const passwordInternalError = (message) => new AuthInternalError({
1152
+ code: "internal_error",
1153
+ message,
1154
+ });
1155
+ const loginApprovalBadRequest = () => new AuthBadRequestError({
1156
+ code: "bad_request",
1157
+ message: "Invalid login approval request",
1158
+ });
1159
+ const loginApprovalSameDeviceDenied = () => new AuthPolicyDeniedError({
1160
+ code: "policy_denied",
1161
+ message: "Login approval must be completed on the same device",
1162
+ });
1163
+ const loginApprovalNoSessionBindingDenied = () => new AuthPolicyDeniedError({
1164
+ code: "policy_denied",
1165
+ message: "Login approval does not create a user session",
1166
+ });
1167
+ const loginApprovalReviewNotConfigured = () => new AuthPolicyDeniedError({
1168
+ code: "policy_denied",
1169
+ message: "Login approval review is not configured",
1170
+ });
1171
+ const loginApprovalFinalizeNotConfigured = () => new AuthPolicyDeniedError({
1172
+ code: "policy_denied",
1173
+ message: "Login approval finalization is not configured",
1174
+ });
1175
+ const loginApprovalPolicyDenied = (reason) => new AuthPolicyDeniedError({
1176
+ code: "policy_denied",
1177
+ message: reason ?? "Login approval denied",
1178
+ });
1179
+ const loginNotificationNotConfigured = () => new AuthPolicyDeniedError({
1180
+ code: "policy_denied",
1181
+ message: "Login notification reporting is not configured",
1182
+ });
1183
+ const loginNotificationBadRequest = () => new AuthBadRequestError({
1184
+ code: "bad_request",
1185
+ message: "Invalid login notification report",
1186
+ });
1187
+ const oauthBadRequest = (message = "Invalid OAuth request") => new AuthBadRequestError({
1188
+ code: "bad_request",
1189
+ message,
1190
+ });
1191
+ const oauthInternalError = (message = "Failed to complete OAuth request") => new AuthInternalError({
1192
+ code: "internal_error",
1193
+ message,
1194
+ });
1195
+ const oauthHookHttpError = (error, internalMessage) => error instanceof AuthBadRequestError || error instanceof AuthUnauthenticatedError
1196
+ ? error
1197
+ : oauthInternalError(internalMessage);
1198
+ const oauthLinkConfirmationHttpError = (error, internalMessage) => error.message === "OAuth provider account is already linked to this user" ||
1199
+ error.message === "OAuth provider account is linked to a different user" ||
1200
+ error.message === "Invalid OAuth link confirmation challenge" ||
1201
+ error.message === "OAuth link confirmation does not match current user" ||
1202
+ error.message === "OAuth link confirmation provider mismatch" ||
1203
+ error.message === "OAuth link confirmation provider account mismatch"
1204
+ ? oauthBadRequest(error.message)
1205
+ : oauthInternalError(internalMessage);
1206
+ const passkeyInternalError = (message = "Failed to complete passkey request") => new AuthInternalError({
1207
+ code: "internal_error",
1208
+ message,
1209
+ });
1210
+ const passkeyBadRequest = (message = "Invalid passkey request") => new AuthBadRequestError({
1211
+ code: "bad_request",
1212
+ message,
1213
+ });
1214
+ const passkeyVerificationHttpError = (error) => error.message === "Failed to load passkey credential" ||
1215
+ error.message === "Failed to store passkey credential" ||
1216
+ error.message === "Failed to update passkey credential" ||
1217
+ error.message === "Failed to generate passkey credential record id"
1218
+ ? passkeyInternalError()
1219
+ : passkeyBadRequest();
1220
+ const passkeyCredentialManagementHttpError = (error) => error.message === "Passkey credential not found"
1221
+ ? passkeyBadRequest("Invalid passkey credential")
1222
+ : passkeyInternalError("Failed to update passkey credentials");
1223
+ const totpInternalError = (message = "Failed to complete TOTP request") => new AuthInternalError({
1224
+ code: "internal_error",
1225
+ message,
1226
+ });
1227
+ const totpBadRequest = (message = "Invalid TOTP request") => new AuthBadRequestError({
1228
+ code: "bad_request",
1229
+ message,
1230
+ });
1231
+ const totpFactorManagementHttpError = (error) => {
1232
+ switch (error.message) {
1233
+ case "Failed to build TOTP enrollment URI":
1234
+ case "TOTP factor not found":
1235
+ case "TOTP factor already confirmed":
1236
+ case "Invalid TOTP code": {
1237
+ return totpBadRequest();
1238
+ }
1239
+ default: {
1240
+ return totpInternalError();
1241
+ }
1242
+ }
1243
+ };
1244
+ const recoveryCodeInternalError = (message = "Failed to complete recovery code request") => new AuthInternalError({
1245
+ code: "internal_error",
1246
+ message,
1247
+ });
1248
+ const recoveryCodeBadRequest = (message = "Invalid recovery code request") => new AuthBadRequestError({
1249
+ code: "bad_request",
1250
+ message,
1251
+ });
1252
+ const recoveryCodeManagementHttpError = (error) => {
1253
+ switch (error.message) {
1254
+ case "Recovery code not found": {
1255
+ return recoveryCodeBadRequest();
1256
+ }
1257
+ default: {
1258
+ return recoveryCodeInternalError();
1259
+ }
1260
+ }
1261
+ };
1262
+ const apiKeyInternalError = (message = "Failed to complete API key request") => new AuthInternalError({
1263
+ code: "internal_error",
1264
+ message,
1265
+ });
1266
+ const apiKeyBadRequest = (message = "Invalid API key request") => new AuthBadRequestError({
1267
+ code: "bad_request",
1268
+ message,
1269
+ });
1270
+ const apiKeyManagementHttpError = (error) => {
1271
+ switch (error.message) {
1272
+ case "API key not found": {
1273
+ return apiKeyBadRequest();
1274
+ }
1275
+ default: {
1276
+ return apiKeyInternalError();
1277
+ }
1278
+ }
1279
+ };
1280
+ const refreshTokenInternalError = (message = "Failed to complete refresh token request") => new AuthInternalError({
1281
+ code: "internal_error",
1282
+ message,
1283
+ });
1284
+ const refreshTokenInvalidCredentials = (message = "Invalid refresh token") => new AuthInvalidCredentialsError({
1285
+ code: "invalid_credentials",
1286
+ message,
1287
+ });
1288
+ const jwtInternalError = (message = "Failed to complete JWT request") => new AuthInternalError({
1289
+ code: "internal_error",
1290
+ message,
1291
+ });
1292
+ const jwtBadRequest = (message = "Invalid JWT request") => new AuthBadRequestError({
1293
+ code: "bad_request",
1294
+ message,
1295
+ });
1296
+ const jwtRevocationHttpError = (error) => error.message === "JWT ID must not be empty" ? jwtBadRequest() : jwtInternalError();
1297
+ const mfaInternalError = (message = "Failed to complete MFA request") => new AuthInternalError({
1298
+ code: "internal_error",
1299
+ message,
1300
+ });
1301
+ const mfaBadRequest = (message = "Invalid MFA request") => new AuthBadRequestError({
1302
+ code: "bad_request",
1303
+ message,
1304
+ });
1305
+ const mfaInvalidCredentials = () => new AuthInvalidCredentialsError({
1306
+ code: "invalid_credentials",
1307
+ message: "Invalid MFA code",
1308
+ });
1309
+ const mfaPolicyDenied = (reason) => new AuthPolicyDeniedError({
1310
+ code: "policy_denied",
1311
+ message: reason ?? "MFA policy denied the request",
1312
+ });
1313
+ const authFlowMfaHttpError = (error) => error._tag === "AuthFlowStateError" ? mfaBadRequest() : mfaInternalError();
1314
+ const stepUpInternalError = (message = "Failed to complete step-up request") => new AuthInternalError({
1315
+ code: "internal_error",
1316
+ message,
1317
+ });
1318
+ const stepUpBadRequest = (message = "Invalid step-up request") => new AuthBadRequestError({
1319
+ code: "bad_request",
1320
+ message,
1321
+ });
1322
+ const stepUpInvalidCredentials = () => new AuthInvalidCredentialsError({
1323
+ code: "invalid_credentials",
1324
+ message: "Invalid step-up factor",
1325
+ });
1326
+ const stepUpPolicyDenied = (message = "Step-up policy denied the request") => new AuthPolicyDeniedError({
1327
+ code: "policy_denied",
1328
+ message,
1329
+ });
1330
+ const trustedDeviceSetCookies = (dependencies) => Effect.gen(function* () {
1331
+ if (!dependencies.rememberDevice ||
1332
+ dependencies.trustedDevice === undefined ||
1333
+ dependencies.trustedDeviceCookie === undefined) {
1334
+ return [];
1335
+ }
1336
+ const token = yield* dependencies.trustedDevice
1337
+ .trust({ userId: dependencies.userId })
1338
+ .pipe(Effect.mapError(() => passwordInternalError("Failed to remember trusted device")));
1339
+ const cookie = yield* dependencies.trustedDeviceCookie
1340
+ .commit({ token })
1341
+ .pipe(Effect.mapError(() => passwordInternalError("Failed to remember trusted device")));
1342
+ return [cookie];
1343
+ });
1344
+ const catchAuthApiRateLimit = (effect, internalMessage) => effect.pipe(Effect.catchTag("RateLimitExceededError", (error) => Effect.fail(rateLimited(error.retryAfter))), Effect.catchTag("RateLimitStoreError", () => Effect.fail(passwordInternalError(internalMessage))), Effect.catchTag("PrivacyError", () => Effect.fail(passwordInternalError(internalMessage))));
1345
+ export class AdminSessionAuthorization extends Context.Service()("auth/AdminSessionAuthorization") {
1346
+ }
1347
+ (function (AdminSessionAuthorization) {
1348
+ AdminSessionAuthorization.make = (service) => AdminSessionAuthorization.of(service);
1349
+ })(AdminSessionAuthorization || (AdminSessionAuthorization = {}));
1350
+ export class AdminSecurityTimelineAuthorization extends Context.Service()("auth/AdminSecurityTimelineAuthorization") {
1351
+ }
1352
+ (function (AdminSecurityTimelineAuthorization) {
1353
+ AdminSecurityTimelineAuthorization.make = (service) => AdminSecurityTimelineAuthorization.of(service);
1354
+ })(AdminSecurityTimelineAuthorization || (AdminSecurityTimelineAuthorization = {}));
1355
+ export class AdminTrustedDeviceAuthorization extends Context.Service()("auth/AdminTrustedDeviceAuthorization") {
1356
+ }
1357
+ (function (AdminTrustedDeviceAuthorization) {
1358
+ AdminTrustedDeviceAuthorization.make = (service) => AdminTrustedDeviceAuthorization.of(service);
1359
+ })(AdminTrustedDeviceAuthorization || (AdminTrustedDeviceAuthorization = {}));
1360
+ export class OidcDiscoveryMetadata extends Context.Service()("auth/OidcDiscoveryMetadata") {
1361
+ }
1362
+ (function (OidcDiscoveryMetadata) {
1363
+ OidcDiscoveryMetadata.make = (service) => OidcDiscoveryMetadata.of(service);
1364
+ })(OidcDiscoveryMetadata || (OidcDiscoveryMetadata = {}));
1365
+ export const OidcDiscoveryMetadataLive = (metadata) => Layer.succeed(OidcDiscoveryMetadata, OidcDiscoveryMetadata.make({ load: () => Effect.succeed(metadata) }));
1366
+ export const makePasswordSignInHandler = (dependencies) => Effect.fn("auth.http.password.sign_in")(function* ({ payload, request, }) {
1367
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.sign_in");
1368
+ const trustedDeviceToken = yield* trustedDeviceTokenFromRequest(dependencies.trustedDeviceCookie, request).pipe(Effect.mapError(() => passwordInternalError("Failed to read trusted device cookie")));
1369
+ const requestMetadataOptions = yield* authRequestMetadataOptions;
1370
+ const requestContext = loginRequestContextFromRequest(request, requestMetadataOptions);
1371
+ const input = passwordSignInInput(payload, Option.isSome(trustedDeviceToken) ? trustedDeviceToken.value : undefined, requestContext);
1372
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1373
+ yield* catchAuthApiRateLimit(authApiRateLimit.passwordSignIn(input), "Failed to sign in with password");
1374
+ const result = yield* dependencies.password.signIn(input).pipe(Effect.catchTag("StorageError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("PasswordHashError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("TrustedDeviceError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("LoginRiskError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("SessionCreateError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("AuthFlowStateError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("LoginApprovalReviewError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))), Effect.catchTag("LoginApprovalFlowStartError", () => Effect.fail(passwordInternalError("Failed to sign in with password"))));
1375
+ yield* startRequiredEmailVerification(dependencies, result);
1376
+ return yield* dependencies.authHttp.commitPasswordSignInResult(result);
1377
+ });
1378
+ export const makePasswordSignUpHandler = (dependencies) => Effect.fn("auth.http.password.sign_up")(function* ({ payload, request, }) {
1379
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.sign_up");
1380
+ const requestMetadataOptions = yield* authRequestMetadataOptions;
1381
+ const input = passwordSignUpInput(payload, loginRequestContextFromRequest(request, requestMetadataOptions));
1382
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1383
+ yield* catchAuthApiRateLimit(authApiRateLimit.passwordSignUp(input), "Failed to sign up with password");
1384
+ const result = yield* dependencies.registration.signUp(input).pipe(Effect.catchTag("EmailAlreadyRegisteredError", () => Effect.fail(new AuthEmailAlreadyRegisteredError({
1385
+ code: "email_already_registered",
1386
+ message: "Email is already registered",
1387
+ }))), Effect.catchTag("StorageError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("PasswordHashError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("CryptoError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("TrustedDeviceError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("LoginRiskError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("SessionCreateError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("AuthFlowStateError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("LoginApprovalReviewError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))), Effect.catchTag("LoginApprovalFlowStartError", () => Effect.fail(passwordInternalError("Failed to sign up with password"))));
1388
+ yield* startRequiredEmailVerification(dependencies, result);
1389
+ return yield* dependencies.authHttp.commitPasswordSignUpResult(result);
1390
+ });
1391
+ export const makePasswordResetStartHandler = (dependencies) => Effect.fn("auth.http.password.reset_start")(function* ({ payload, }) {
1392
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.reset_start");
1393
+ const input = passwordResetStartInput(payload);
1394
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1395
+ yield* catchAuthApiRateLimit(authApiRateLimit.passwordResetStart(input), "Failed to start password reset");
1396
+ yield* dependencies.passwordReset.start(input).pipe(Effect.mapError(() => new AuthInternalError({
1397
+ code: "internal_error",
1398
+ message: "Failed to start password reset",
1399
+ })));
1400
+ return HttpServerResponse.empty({ status: 204 });
1401
+ });
1402
+ export const makePasswordResetVerifyHandler = (dependencies) => Effect.fn("auth.http.password.reset_verify")(function* ({ payload, }) {
1403
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.reset_verify");
1404
+ yield* dependencies.passwordReset
1405
+ .verify(passwordResetVerifyInput(payload))
1406
+ .pipe(Effect.mapError(() => new AuthBadRequestError({
1407
+ code: "bad_request",
1408
+ message: "Invalid password reset request",
1409
+ })));
1410
+ return HttpServerResponse.empty({ status: 204 });
1411
+ });
1412
+ const passwordManagementError = (error) => error.reason === "internal"
1413
+ ? new AuthInternalError({
1414
+ code: "internal_error",
1415
+ message: "Failed to update password",
1416
+ })
1417
+ : new AuthBadRequestError({
1418
+ code: "bad_request",
1419
+ message: "Invalid password update request",
1420
+ });
1421
+ export const makePasswordSetHandler = (dependencies) => Effect.fn("auth.http.password.set")(function* ({ payload, request, }) {
1422
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.set");
1423
+ const current = yield* readRequiredSession(dependencies, request);
1424
+ yield* dependencies.passwordManagement
1425
+ .set(passwordSetInput(current.currentSession.userId, payload))
1426
+ .pipe(Effect.mapError(passwordManagementError));
1427
+ return HttpServerResponse.empty({ status: 204 });
1428
+ });
1429
+ export const makePasswordChangeHandler = (dependencies) => Effect.fn("auth.http.password.change")(function* ({ payload, request, }) {
1430
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "password.change");
1431
+ const current = yield* readRequiredSession(dependencies, request);
1432
+ yield* dependencies.passwordManagement
1433
+ .change(passwordChangeInput(current.currentSession.userId, payload))
1434
+ .pipe(Effect.mapError(passwordManagementError));
1435
+ return HttpServerResponse.empty({ status: 204 });
1436
+ });
1437
+ export const makeCurrentSessionHandler = (dependencies) => Effect.fn("auth.http.session.current")(function* ({ request, }) {
1438
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.current");
1439
+ const tokenOption = yield* dependencies.sessionCookie
1440
+ .read(webRequestFromHeaders(request.headers))
1441
+ .pipe(Effect.mapError((error) => error.cause === undefined
1442
+ ? new AuthUnauthenticatedError({
1443
+ code: "unauthenticated",
1444
+ message: "Unauthenticated",
1445
+ })
1446
+ : new AuthInternalError({
1447
+ code: "internal_error",
1448
+ message: "Failed to validate session",
1449
+ })));
1450
+ if (Option.isNone(tokenOption)) {
1451
+ return yield* new AuthUnauthenticatedError({
1452
+ code: "unauthenticated",
1453
+ message: "Unauthenticated",
1454
+ });
1455
+ }
1456
+ const session = yield* dependencies.sessions
1457
+ .validate(tokenOption.value)
1458
+ .pipe(Effect.mapError((error) => error.cause === undefined
1459
+ ? new AuthUnauthenticatedError({
1460
+ code: "unauthenticated",
1461
+ message: "Unauthenticated",
1462
+ })
1463
+ : new AuthInternalError({
1464
+ code: "internal_error",
1465
+ message: "Failed to validate session",
1466
+ })));
1467
+ return yield* dependencies.authHttp.commitCurrentSession(session);
1468
+ });
1469
+ export const makeRefreshSessionHandler = (dependencies) => Effect.fn("auth.http.session.refresh")(function* ({ request, }) {
1470
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.refresh");
1471
+ const tokenOption = yield* dependencies.sessionCookie
1472
+ .read(webRequestFromHeaders(request.headers))
1473
+ .pipe(Effect.mapError((error) => error.cause === undefined
1474
+ ? new AuthUnauthenticatedError({
1475
+ code: "unauthenticated",
1476
+ message: "Unauthenticated",
1477
+ })
1478
+ : new AuthInternalError({
1479
+ code: "internal_error",
1480
+ message: "Failed to validate session",
1481
+ })));
1482
+ if (Option.isNone(tokenOption)) {
1483
+ return yield* new AuthUnauthenticatedError({
1484
+ code: "unauthenticated",
1485
+ message: "Unauthenticated",
1486
+ });
1487
+ }
1488
+ const session = yield* dependencies.sessions
1489
+ .refresh(tokenOption.value)
1490
+ .pipe(Effect.mapError((error) => error.cause === undefined
1491
+ ? new AuthUnauthenticatedError({
1492
+ code: "unauthenticated",
1493
+ message: "Unauthenticated",
1494
+ })
1495
+ : new AuthInternalError({
1496
+ code: "internal_error",
1497
+ message: "Failed to refresh session",
1498
+ })));
1499
+ return yield* dependencies.authHttp.commitSessionRefreshed(session);
1500
+ });
1501
+ export const makeLogoutHandler = (dependencies) => Effect.fn("auth.http.session.logout")(function* ({ request, }) {
1502
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.logout");
1503
+ const tokenOption = yield* dependencies.sessionCookie
1504
+ .read(webRequestFromHeaders(request.headers))
1505
+ .pipe(Effect.catchTag("SessionValidateError", (error) => error.cause === undefined
1506
+ ? Effect.succeed(Option.none())
1507
+ : Effect.fail(new AuthInternalError({
1508
+ code: "internal_error",
1509
+ message: "Failed to validate session",
1510
+ }))));
1511
+ if (Option.isSome(tokenOption)) {
1512
+ const sessionOption = yield* dependencies.sessions
1513
+ .validate(tokenOption.value)
1514
+ .pipe(Effect.map(Option.some), Effect.catchTag("SessionValidateError", (error) => error.cause === undefined
1515
+ ? Effect.succeed(Option.none())
1516
+ : Effect.fail(new AuthInternalError({
1517
+ code: "internal_error",
1518
+ message: "Failed to validate session",
1519
+ }))));
1520
+ if (Option.isSome(sessionOption)) {
1521
+ yield* dependencies.sessions
1522
+ .revoke({
1523
+ sessionId: sessionOption.value.currentSession.sessionId,
1524
+ reason: "logout",
1525
+ })
1526
+ .pipe(Effect.mapError(() => new AuthInternalError({
1527
+ code: "internal_error",
1528
+ message: "Failed to revoke session",
1529
+ })));
1530
+ }
1531
+ }
1532
+ return yield* dependencies.authHttp.commitSessionCleared();
1533
+ });
1534
+ export const makeListSessionsHandler = (dependencies) => Effect.fn("auth.http.session.list")(function* ({ request, }) {
1535
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.list");
1536
+ const current = yield* readRequiredSession(dependencies, request);
1537
+ const sessions = yield* dependencies.sessions
1538
+ .listForUser({ userId: current.currentSession.userId })
1539
+ .pipe(Effect.mapError(() => new AuthInternalError({
1540
+ code: "internal_error",
1541
+ message: "Failed to list sessions",
1542
+ })));
1543
+ return {
1544
+ sessions: sessions.map((session) => activeSessionBody(session, current.currentSession.sessionId)),
1545
+ };
1546
+ });
1547
+ export const makeRevokeSessionHandler = (dependencies) => Effect.fn("auth.http.session.revoke")(function* ({ payload, request, }) {
1548
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.revoke");
1549
+ const current = yield* readRequiredSession(dependencies, request);
1550
+ yield* dependencies.sessions
1551
+ .revokeForUser({
1552
+ userId: current.currentSession.userId,
1553
+ sessionId: payload.sessionId,
1554
+ reason: "user_revoked_session",
1555
+ })
1556
+ .pipe(Effect.mapError(() => new AuthInternalError({
1557
+ code: "internal_error",
1558
+ message: "Failed to revoke session",
1559
+ })));
1560
+ return payload.sessionId === current.currentSession.sessionId
1561
+ ? yield* dependencies.authHttp.commitSessionCleared()
1562
+ : HttpServerResponse.empty({ status: 204 });
1563
+ });
1564
+ export const makeRevokeOtherSessionsHandler = (dependencies) => Effect.fn("auth.http.session.revoke_others")(function* ({ request, }) {
1565
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "session.revoke_others");
1566
+ const current = yield* readRequiredSession(dependencies, request);
1567
+ yield* dependencies.sessions
1568
+ .revokeAllForUserExcept({
1569
+ userId: current.currentSession.userId,
1570
+ exceptSessionId: current.currentSession.sessionId,
1571
+ reason: "user_revoked_other_sessions",
1572
+ })
1573
+ .pipe(Effect.mapError(() => new AuthInternalError({
1574
+ code: "internal_error",
1575
+ message: "Failed to revoke other sessions",
1576
+ })));
1577
+ return HttpServerResponse.empty({ status: 204 });
1578
+ });
1579
+ export const makeAdminSessionListHandler = (dependencies) => Effect.fn("auth.http.admin_session.list")(function* ({ query, request, }) {
1580
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_session.list");
1581
+ const current = yield* readRequiredSession(dependencies, request);
1582
+ yield* dependencies.authorization.authorize({
1583
+ currentSession: current.currentSession,
1584
+ targetUserId: query.userId,
1585
+ action: "list",
1586
+ request,
1587
+ });
1588
+ const sessions = yield* dependencies.sessions
1589
+ .listForUser({ userId: query.userId })
1590
+ .pipe(Effect.mapError(() => new AuthInternalError({
1591
+ code: "internal_error",
1592
+ message: "Failed to list admin sessions",
1593
+ })));
1594
+ return { sessions: sessions.map(adminSessionHttpBody) };
1595
+ });
1596
+ export const makeAdminSessionRevokeHandler = (dependencies) => Effect.fn("auth.http.admin_session.revoke")(function* ({ payload, request, }) {
1597
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_session.revoke");
1598
+ const current = yield* readRequiredSession(dependencies, request);
1599
+ yield* dependencies.authorization.authorize({
1600
+ currentSession: current.currentSession,
1601
+ targetUserId: payload.userId,
1602
+ action: "revoke",
1603
+ request,
1604
+ sessionId: payload.sessionId,
1605
+ });
1606
+ yield* dependencies.sessions
1607
+ .revokeForUser({
1608
+ userId: payload.userId,
1609
+ sessionId: payload.sessionId,
1610
+ reason: "admin_revoked_session",
1611
+ })
1612
+ .pipe(Effect.mapError(() => new AuthInternalError({
1613
+ code: "internal_error",
1614
+ message: "Failed to revoke admin session",
1615
+ })));
1616
+ return HttpServerResponse.empty({ status: 204 });
1617
+ });
1618
+ export const makeAdminSessionRevokeAllHandler = (dependencies) => Effect.fn("auth.http.admin_session.revoke_all")(function* ({ payload, request, }) {
1619
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_session.revoke_all");
1620
+ const current = yield* readRequiredSession(dependencies, request);
1621
+ yield* dependencies.authorization.authorize({
1622
+ currentSession: current.currentSession,
1623
+ targetUserId: payload.userId,
1624
+ action: "revoke_all",
1625
+ request,
1626
+ });
1627
+ yield* dependencies.sessions.revokeAllForUser(payload.userId).pipe(Effect.mapError(() => new AuthInternalError({
1628
+ code: "internal_error",
1629
+ message: "Failed to revoke admin sessions",
1630
+ })));
1631
+ return HttpServerResponse.empty({ status: 204 });
1632
+ });
1633
+ export const makeLoginNotificationReportHandler = (dependencies) => Effect.fn("auth.http.security.login_notification.report")(function* ({ payload, }) {
1634
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "security.login_notification.report");
1635
+ if (dependencies.loginNotification === undefined) {
1636
+ return yield* loginNotificationNotConfigured();
1637
+ }
1638
+ yield* dependencies.loginNotification
1639
+ .report(loginNotificationReportInput(payload))
1640
+ .pipe(Effect.mapError((error) => error.reason === "invalid_report"
1641
+ ? loginNotificationBadRequest()
1642
+ : new AuthInternalError({
1643
+ code: "internal_error",
1644
+ message: "Failed to process login notification report",
1645
+ })));
1646
+ return HttpServerResponse.empty({ status: 204 });
1647
+ });
1648
+ const securityTimelineActorHttpBody = (actor) => actor.type === "anonymous"
1649
+ ? { type: "anonymous" }
1650
+ : {
1651
+ type: "user",
1652
+ ...(actor.sessionId === undefined ? {} : { sessionId: actor.sessionId }),
1653
+ };
1654
+ const securityTimelineRequestHttpBody = (request) => ({
1655
+ ...(request.ipHash === undefined ? {} : { ipHash: request.ipHash }),
1656
+ ...(request.userAgentHash === undefined
1657
+ ? {}
1658
+ : { userAgentHash: request.userAgentHash }),
1659
+ });
1660
+ export const securityTimelineEventHttpBody = (event) => ({
1661
+ eventId: event.id,
1662
+ type: event.type,
1663
+ category: event.category,
1664
+ severity: event.severity,
1665
+ occurredAt: event.occurredAt,
1666
+ summary: event.summary,
1667
+ ...(event.actor === undefined
1668
+ ? {}
1669
+ : { actor: securityTimelineActorHttpBody(event.actor) }),
1670
+ ...(event.request === undefined
1671
+ ? {}
1672
+ : { request: securityTimelineRequestHttpBody(event.request) }),
1673
+ ...(event.metadata === undefined ? {} : { metadata: event.metadata }),
1674
+ });
1675
+ const securityTimelineListInput = (query, userId) => ({
1676
+ userId,
1677
+ ...(query.limit === undefined ? {} : { limit: query.limit }),
1678
+ ...(query.beforeOccurredAt === undefined
1679
+ ? {}
1680
+ : { beforeOccurredAt: query.beforeOccurredAt }),
1681
+ ...(query.types === undefined ? {} : { types: query.types }),
1682
+ ...(query.categories === undefined ? {} : { categories: query.categories }),
1683
+ });
1684
+ const adminSecurityTimelineListInput = (query) => securityTimelineListInput(query, query.userId);
1685
+ export const makeSecurityTimelineListHandler = (dependencies) => Effect.fn("auth.http.security_timeline.list")(function* ({ query, request, }) {
1686
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "security_timeline.list");
1687
+ const current = yield* readRequiredSession(dependencies, request);
1688
+ const events = yield* dependencies.securityTimeline
1689
+ .listByUser(securityTimelineListInput(query, current.currentSession.userId))
1690
+ .pipe(Effect.mapError(() => new AuthInternalError({
1691
+ code: "internal_error",
1692
+ message: "Failed to list security timeline",
1693
+ })));
1694
+ return { events: events.map(securityTimelineEventHttpBody) };
1695
+ });
1696
+ export const makeAdminSecurityTimelineListHandler = (dependencies) => Effect.fn("auth.http.admin_security_timeline.list")(function* ({ query, request, }) {
1697
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_security_timeline.list");
1698
+ const current = yield* readRequiredSession(dependencies, request);
1699
+ yield* dependencies.authorization.authorize({
1700
+ currentSession: current.currentSession,
1701
+ targetUserId: query.userId,
1702
+ request,
1703
+ });
1704
+ const events = yield* dependencies.securityTimeline
1705
+ .listByUser(adminSecurityTimelineListInput(query))
1706
+ .pipe(Effect.mapError(() => new AuthInternalError({
1707
+ code: "internal_error",
1708
+ message: "Failed to list admin security timeline",
1709
+ })));
1710
+ return { events: events.map(securityTimelineEventHttpBody) };
1711
+ });
1712
+ export const trustedDeviceHttpBody = (device) => ({
1713
+ deviceId: device.tokenHash,
1714
+ createdAt: device.createdAt,
1715
+ lastSeenAt: device.lastSeenAt,
1716
+ expiresAt: device.expiresAt,
1717
+ ...(device.metadata === undefined ? {} : { metadata: device.metadata }),
1718
+ });
1719
+ export const makeTrustedDeviceListHandler = (dependencies) => Effect.fn("auth.http.trusted_device.list")(function* ({ request, }) {
1720
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "trusted_device.list");
1721
+ const current = yield* readRequiredSession(dependencies, request);
1722
+ const now = yield* currentUnixMillis;
1723
+ const devices = yield* dependencies.trustedDevices
1724
+ .listForUser({ userId: current.currentSession.userId, now })
1725
+ .pipe(Effect.mapError(() => new AuthInternalError({
1726
+ code: "internal_error",
1727
+ message: "Failed to list trusted devices",
1728
+ })));
1729
+ return { devices: devices.map(trustedDeviceHttpBody) };
1730
+ });
1731
+ export const makeTrustedDeviceRevokeHandler = (dependencies) => Effect.fn("auth.http.trusted_device.revoke")(function* ({ payload, request, }) {
1732
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "trusted_device.revoke");
1733
+ const current = yield* readRequiredSession(dependencies, request);
1734
+ yield* dependencies.trustedDevices
1735
+ .revokeForUser({
1736
+ userId: current.currentSession.userId,
1737
+ tokenHash: payload.deviceId,
1738
+ })
1739
+ .pipe(Effect.mapError(() => new AuthInternalError({
1740
+ code: "internal_error",
1741
+ message: "Failed to revoke trusted device",
1742
+ })));
1743
+ return HttpServerResponse.empty({ status: 204 });
1744
+ });
1745
+ export const makeAdminTrustedDeviceListHandler = (dependencies) => Effect.fn("auth.http.admin_trusted_device.list")(function* ({ query, request, }) {
1746
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_trusted_device.list");
1747
+ const current = yield* readRequiredSession(dependencies, request);
1748
+ yield* dependencies.authorization.authorize({
1749
+ currentSession: current.currentSession,
1750
+ targetUserId: query.userId,
1751
+ action: "list",
1752
+ request,
1753
+ });
1754
+ const now = yield* currentUnixMillis;
1755
+ const devices = yield* dependencies.trustedDevices
1756
+ .listForUser({ userId: query.userId, now })
1757
+ .pipe(Effect.mapError(() => new AuthInternalError({
1758
+ code: "internal_error",
1759
+ message: "Failed to list admin trusted devices",
1760
+ })));
1761
+ return { devices: devices.map(trustedDeviceHttpBody) };
1762
+ });
1763
+ export const makeAdminTrustedDeviceRevokeHandler = (dependencies) => Effect.fn("auth.http.admin_trusted_device.revoke")(function* ({ payload, request, }) {
1764
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "admin_trusted_device.revoke");
1765
+ const current = yield* readRequiredSession(dependencies, request);
1766
+ yield* dependencies.authorization.authorize({
1767
+ currentSession: current.currentSession,
1768
+ targetUserId: payload.userId,
1769
+ action: "revoke",
1770
+ request,
1771
+ deviceId: payload.deviceId,
1772
+ });
1773
+ yield* dependencies.trustedDevices
1774
+ .revokeForUser({
1775
+ userId: payload.userId,
1776
+ tokenHash: payload.deviceId,
1777
+ })
1778
+ .pipe(Effect.mapError(() => new AuthInternalError({
1779
+ code: "internal_error",
1780
+ message: "Failed to revoke admin trusted device",
1781
+ })));
1782
+ return HttpServerResponse.empty({ status: 204 });
1783
+ });
1784
+ export const makeEmailVerificationStartHandler = (dependencies) => Effect.fn("auth.http.email_verification.start")(function* ({ payload, }) {
1785
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "email_verification.start");
1786
+ const input = emailVerificationStartInput(payload);
1787
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1788
+ yield* catchAuthApiRateLimit(authApiRateLimit.emailVerificationStart(input), "Failed to start email verification");
1789
+ yield* dependencies.emailVerificationFlow.start(input).pipe(Effect.catchTag("EmailVerificationFlowStartError", (error) => Effect.fail(error.cause instanceof EmailVerificationIssueError
1790
+ ? new AuthBadRequestError({
1791
+ code: "bad_request",
1792
+ message: "Invalid email verification request",
1793
+ })
1794
+ : error.cause instanceof EmailDeliveryError
1795
+ ? new AuthInternalError({
1796
+ code: "internal_error",
1797
+ message: "Failed to send email verification",
1798
+ })
1799
+ : new AuthInternalError({
1800
+ code: "internal_error",
1801
+ message: "Failed to start email verification",
1802
+ }))));
1803
+ return HttpServerResponse.empty({ status: 204 });
1804
+ });
1805
+ export const makeEmailVerificationVerifyHandler = (dependencies) => Effect.fn("auth.http.email_verification.verify")(function* ({ payload, request, }) {
1806
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "email_verification.verify");
1807
+ const verified = yield* dependencies.emailVerification
1808
+ .verify(emailVerificationVerifyInput(payload))
1809
+ .pipe(Effect.mapError(() => new AuthBadRequestError({
1810
+ code: "bad_request",
1811
+ message: "Invalid email verification request",
1812
+ })));
1813
+ yield* upgradeVerifiedEmailSession(dependencies, request, verified);
1814
+ return HttpServerResponse.empty({ status: 204 });
1815
+ });
1816
+ export const makeEmailOtpStartHandler = (dependencies) => Effect.fn("auth.http.email_otp.start")(function* ({ payload, }) {
1817
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "email_otp.start");
1818
+ const input = emailOtpStartInput(payload);
1819
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1820
+ yield* catchAuthApiRateLimit(authApiRateLimit.emailOtpStart(input), "Failed to start email OTP");
1821
+ return yield* dependencies.emailOtp.start(input).pipe(Effect.mapError(() => new AuthInternalError({
1822
+ code: "internal_error",
1823
+ message: "Failed to start email OTP",
1824
+ })));
1825
+ });
1826
+ export const makeEmailOtpVerifyHandler = (dependencies) => Effect.fn("auth.http.email_otp.verify")(function* ({ payload, request, }) {
1827
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "email_otp.verify");
1828
+ const trustedDeviceToken = yield* trustedDeviceTokenFromRequest(dependencies.trustedDeviceCookie, request).pipe(Effect.mapError(() => passwordInternalError("Failed to read trusted device cookie")));
1829
+ const requestMetadataOptions = yield* authRequestMetadataOptions;
1830
+ const requestContext = loginRequestContextFromRequest(request, requestMetadataOptions);
1831
+ const result = yield* dependencies.emailOtp
1832
+ .verify(emailOtpVerifyInput(payload, Option.isSome(trustedDeviceToken)
1833
+ ? trustedDeviceToken.value
1834
+ : undefined, requestContext))
1835
+ .pipe(Effect.mapError(() => new AuthInternalError({
1836
+ code: "internal_error",
1837
+ message: "Failed to verify email OTP",
1838
+ })));
1839
+ return yield* dependencies.authHttp.commitEmailOtpVerifyResult(result);
1840
+ });
1841
+ export const makeMagicLinkStartHandler = (dependencies) => Effect.fn("auth.http.magic_link.start")(function* ({ payload, }) {
1842
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "magic_link.start");
1843
+ const input = magicLinkStartInput(payload);
1844
+ const authApiRateLimit = dependencies.authApiRateLimit ?? noopAuthApiRateLimit;
1845
+ yield* catchAuthApiRateLimit(authApiRateLimit.magicLinkStart(input), "Failed to start magic link");
1846
+ const started = yield* dependencies.magicLink.start(input).pipe(Effect.mapError(() => new AuthInternalError({
1847
+ code: "internal_error",
1848
+ message: "Failed to start magic link",
1849
+ })));
1850
+ return {
1851
+ email: started.email,
1852
+ expiresAt: started.expiresAt,
1853
+ };
1854
+ });
1855
+ export const makeMagicLinkVerifyHandler = (dependencies) => Effect.fn("auth.http.magic_link.verify")(function* ({ payload, request, }) {
1856
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "magic_link.verify");
1857
+ const trustedDeviceToken = yield* trustedDeviceTokenFromRequest(dependencies.trustedDeviceCookie, request).pipe(Effect.mapError(() => passwordInternalError("Failed to read trusted device cookie")));
1858
+ const requestMetadataOptions = yield* authRequestMetadataOptions;
1859
+ const requestContext = loginRequestContextFromRequest(request, requestMetadataOptions);
1860
+ const result = yield* dependencies.magicLink
1861
+ .verify(magicLinkVerifyInput(payload, Option.isSome(trustedDeviceToken)
1862
+ ? trustedDeviceToken.value
1863
+ : undefined, requestContext))
1864
+ .pipe(Effect.mapError(() => new AuthInternalError({
1865
+ code: "internal_error",
1866
+ message: "Failed to verify magic link",
1867
+ })));
1868
+ return yield* dependencies.authHttp.commitMagicLinkVerifyResult(result);
1869
+ });
1870
+ export const makeOAuthAuthorizationStartHandler = (dependencies) => Effect.fn("auth.http.oauth.authorization_start")(function* ({ payload, }) {
1871
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.authorization_start");
1872
+ const provider = yield* dependencies.oauthProviders.get(payload.providerId).pipe(Effect.mapError(() => oauthInternalError("Failed to load OAuth provider")));
1873
+ if (Option.isNone(provider)) {
1874
+ return yield* oauthBadRequest("Unknown OAuth provider");
1875
+ }
1876
+ const started = yield* dependencies.oauthState
1877
+ .start(oauthAuthorizationStartInput(payload, provider.value, dependencies))
1878
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to start OAuth authorization")));
1879
+ if (dependencies.storeCodeVerifier !== undefined) {
1880
+ yield* dependencies.storeCodeVerifier({ payload, started }).pipe(Effect.mapError(() => oauthInternalError("Failed to store OAuth verifier")));
1881
+ }
1882
+ return oauthAuthorizationStartedHttpBody(started);
1883
+ });
1884
+ export const makeOAuthProviderAuthorizationHandler = (dependencies) => Effect.fn("auth.http.oauth.authorize")(function* ({ query, }) {
1885
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.authorize");
1886
+ const result = yield* dependencies.authorization
1887
+ .authorize({
1888
+ responseType: query.response_type,
1889
+ ...(query.client_id === undefined ? {} : { clientId: query.client_id }),
1890
+ ...(query.redirect_uri === undefined
1891
+ ? {}
1892
+ : { redirectUri: query.redirect_uri }),
1893
+ ...(query.scope === undefined ? {} : { scopes: query.scope }),
1894
+ ...(query.state === undefined ? {} : { state: query.state }),
1895
+ ...(query.code_challenge === undefined
1896
+ ? {}
1897
+ : { codeChallenge: query.code_challenge }),
1898
+ ...(query.code_challenge_method === undefined
1899
+ ? {}
1900
+ : { codeChallengeMethod: query.code_challenge_method }),
1901
+ })
1902
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to authorize OAuth request")));
1903
+ if (result.valid) {
1904
+ return oauthAuthorizationRedirect(result.redirectUri, {
1905
+ code: Redacted.value(result.code.code),
1906
+ state: result.state,
1907
+ });
1908
+ }
1909
+ if (result.redirectUri !== undefined) {
1910
+ return oauthAuthorizationRedirect(result.redirectUri, {
1911
+ error: result.reason,
1912
+ error_description: result.errorDescription,
1913
+ state: result.state,
1914
+ });
1915
+ }
1916
+ return yield* oauthAuthorizationEndpointError(result.reason, result.errorDescription);
1917
+ });
1918
+ export const makeOAuthAuthorizationCodeTokenHandler = (dependencies) => Effect.fn("auth.http.oauth.token")(function* ({ request, }) {
1919
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.token");
1920
+ const payload = yield* oauthTokenRequestBody(request);
1921
+ const { clientId, clientAuthenticated } = yield* oauthClientEndpointAuthentication({
1922
+ request,
1923
+ payload,
1924
+ authenticateClient: dependencies.authenticateClient,
1925
+ invalidRequest: () => oauthTokenEndpointError("invalid_request"),
1926
+ invalidClient: () => oauthTokenEndpointError("invalid_client"),
1927
+ });
1928
+ if (payload.grant_type === "refresh_token") {
1929
+ return yield* oauthRefreshTokenResponse({
1930
+ dependencies,
1931
+ payload,
1932
+ ...(clientId === undefined ? {} : { clientId }),
1933
+ clientAuthenticated,
1934
+ });
1935
+ }
1936
+ if (payload.grant_type === "client_credentials") {
1937
+ return yield* oauthClientCredentialsTokenResponse({
1938
+ dependencies,
1939
+ payload,
1940
+ ...(clientId === undefined ? {} : { clientId }),
1941
+ clientAuthenticated,
1942
+ });
1943
+ }
1944
+ return yield* oauthAuthorizationCodeTokenResponse({
1945
+ dependencies,
1946
+ payload,
1947
+ ...(clientId === undefined ? {} : { clientId }),
1948
+ clientAuthenticated,
1949
+ });
1950
+ });
1951
+ export const makeOAuthTokenRevocationHandler = (dependencies) => Effect.fn("auth.http.oauth.revoke")(function* ({ request, }) {
1952
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.revoke");
1953
+ const payload = yield* oauthTokenRevocationRequestBody(request);
1954
+ const { clientId, clientAuthenticated } = yield* oauthClientEndpointAuthentication({
1955
+ request,
1956
+ payload,
1957
+ authenticateClient: dependencies.authenticateClient,
1958
+ invalidRequest: () => oauthTokenRevocationEndpointError("invalid_request"),
1959
+ invalidClient: () => oauthTokenRevocationEndpointError("invalid_client"),
1960
+ });
1961
+ const token = oauthTokenGrantString(payload.token);
1962
+ const tokenTypeHint = oauthTokenGrantString(payload.token_type_hint);
1963
+ const result = yield* dependencies.tokenRevocation
1964
+ .revoke({
1965
+ ...(token === undefined ? {} : { token: Redacted.make(token) }),
1966
+ ...(tokenTypeHint === undefined ? {} : { tokenTypeHint }),
1967
+ ...(clientId === undefined ? {} : { clientId }),
1968
+ clientAuthenticated,
1969
+ })
1970
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to revoke OAuth token")));
1971
+ if (!result.valid) {
1972
+ return yield* oauthTokenRevocationEndpointError(result.reason);
1973
+ }
1974
+ return HttpServerResponse.empty({ status: 204 });
1975
+ });
1976
+ export const makeOAuthTokenIntrospectionHandler = (dependencies) => Effect.fn("auth.http.oauth.introspect")(function* ({ request, }) {
1977
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.introspect");
1978
+ const payload = yield* oauthTokenIntrospectionRequestBody(request);
1979
+ const { clientId, clientAuthenticated } = yield* oauthClientEndpointAuthentication({
1980
+ request,
1981
+ payload,
1982
+ authenticateClient: dependencies.authenticateClient,
1983
+ invalidRequest: () => oauthTokenIntrospectionEndpointError("invalid_request"),
1984
+ invalidClient: () => oauthTokenIntrospectionEndpointError("invalid_client"),
1985
+ });
1986
+ const token = oauthTokenGrantString(payload.token);
1987
+ const tokenTypeHint = oauthTokenGrantString(payload.token_type_hint);
1988
+ const result = yield* dependencies.tokenIntrospection
1989
+ .introspect({
1990
+ ...(token === undefined ? {} : { token: Redacted.make(token) }),
1991
+ ...(tokenTypeHint === undefined ? {} : { tokenTypeHint }),
1992
+ ...(clientId === undefined ? {} : { clientId }),
1993
+ clientAuthenticated,
1994
+ })
1995
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to introspect OAuth token")));
1996
+ if (!result.valid) {
1997
+ return yield* oauthTokenIntrospectionEndpointError(result.reason);
1998
+ }
1999
+ return oauthTokenIntrospectionResponseHttpBody(result.introspection);
2000
+ });
2001
+ const makeOAuthTokenRevocationNotConfiguredHandler = () => Effect.fn("auth.http.oauth.revoke_not_configured")(function* ({ request, }) {
2002
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.revoke");
2003
+ yield* oauthTokenRevocationRequestBody(request);
2004
+ return yield* oauthTokenRevocationEndpointError("invalid_request");
2005
+ });
2006
+ const makeOAuthTokenIntrospectionNotConfiguredHandler = () => Effect.fn("auth.http.oauth.introspect_not_configured")(function* ({ request, }) {
2007
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.introspect");
2008
+ yield* oauthTokenIntrospectionRequestBody(request);
2009
+ return yield* oauthTokenIntrospectionEndpointError("invalid_request");
2010
+ });
2011
+ export const makeOAuthAccountUnlinkHandler = (dependencies) => Effect.fn("auth.http.oauth.account_unlink")(function* ({ payload, request, }) {
2012
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.account_unlink");
2013
+ const session = yield* readRequiredSession(dependencies, request);
2014
+ const stepUpSatisfied = dependencies.stepUpSatisfied === undefined
2015
+ ? undefined
2016
+ : yield* dependencies.stepUpSatisfied({ payload, request, session }).pipe(Effect.mapError(() => oauthInternalError("Failed to evaluate OAuth unlink step-up")));
2017
+ const decision = yield* dependencies.oauthAccountUnlinking
2018
+ .resolve({
2019
+ userId: session.currentSession.userId,
2020
+ providerId: payload.providerId,
2021
+ providerAccountId: payload.providerAccountId,
2022
+ ...(stepUpSatisfied === undefined ? {} : { stepUpSatisfied }),
2023
+ })
2024
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to resolve OAuth account unlinking")));
2025
+ if (decision.type !== "allow") {
2026
+ return oauthAccountUnlinkResolutionHttpBody(decision);
2027
+ }
2028
+ if (dependencies.unlinkAfterAllow !== undefined) {
2029
+ yield* dependencies
2030
+ .unlinkAfterAllow({ payload, request, session, decision })
2031
+ .pipe(Effect.mapError(() => oauthInternalError("Failed to unlink OAuth account")));
2032
+ }
2033
+ return oauthAccountUnlinkResolutionHttpBody(decision, {
2034
+ unlinked: dependencies.unlinkAfterAllow !== undefined,
2035
+ });
2036
+ });
2037
+ export const makeOAuthLinkConfirmationStartHandler = (dependencies) => Effect.fn("auth.http.oauth.link_confirmation_start")(function* ({ payload, request, }) {
2038
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.link_confirmation_start");
2039
+ const baseInput = dependencies.startInput === undefined
2040
+ ? yield* oauthLinkConfirmationStartInput(payload, dependencies)
2041
+ : yield* dependencies.startInput({ payload, request }).pipe(Effect.mapError((error) => oauthHookHttpError(error, "Failed to resolve OAuth link confirmation input")));
2042
+ const input = {
2043
+ ...baseInput,
2044
+ ...(baseInput.ttl === undefined && dependencies.ttl !== undefined
2045
+ ? { ttl: dependencies.ttl }
2046
+ : {}),
2047
+ };
2048
+ const started = yield* dependencies.oauthLinkConfirmation.start(input).pipe(Effect.mapError((error) => oauthLinkConfirmationHttpError(error, "Failed to start OAuth link confirmation")));
2049
+ if (dependencies.onStarted !== undefined) {
2050
+ yield* dependencies.onStarted({ payload, request, started }).pipe(Effect.mapError(() => oauthInternalError("Failed to deliver OAuth link confirmation")));
2051
+ }
2052
+ return oauthLinkConfirmationStartedHttpBody(started);
2053
+ });
2054
+ export const makeOAuthLinkConfirmationInspectHandler = (dependencies) => Effect.fn("auth.http.oauth.link_confirmation_inspect")(function* ({ payload, }) {
2055
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.link_confirmation_inspect");
2056
+ const pending = yield* dependencies.oauthLinkConfirmation
2057
+ .inspect(oauthLinkConfirmationInspectInput(payload))
2058
+ .pipe(Effect.mapError((error) => oauthLinkConfirmationHttpError(error, "Failed to inspect OAuth link confirmation")));
2059
+ return oauthLinkConfirmationPendingHttpBody(pending);
2060
+ });
2061
+ export const makeOAuthLinkConfirmationConfirmHandler = (dependencies) => Effect.fn("auth.http.oauth.link_confirmation_confirm")(function* ({ payload, request, }) {
2062
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oauth.link_confirmation_confirm");
2063
+ const currentUserId = dependencies.currentUserId === undefined
2064
+ ? undefined
2065
+ : yield* dependencies.currentUserId({ payload, request }).pipe(Effect.mapError((error) => oauthHookHttpError(error, "Failed to resolve current OAuth user")));
2066
+ const confirmed = yield* dependencies.oauthLinkConfirmation
2067
+ .confirm(oauthLinkConfirmationConfirmInput(payload, currentUserId))
2068
+ .pipe(Effect.mapError((error) => oauthLinkConfirmationHttpError(error, "Failed to confirm OAuth link confirmation")));
2069
+ if (dependencies.linkAfterConfirm !== undefined) {
2070
+ yield* dependencies.linkAfterConfirm({ payload, request, confirmed }).pipe(Effect.mapError(() => oauthInternalError("Failed to link OAuth account")));
2071
+ }
2072
+ return oauthLinkConfirmationConfirmedHttpBody(confirmed, {
2073
+ linked: dependencies.linkAfterConfirm !== undefined,
2074
+ });
2075
+ });
2076
+ export const makePasskeyRegistrationStartHandler = (dependencies) => Effect.fn("auth.http.passkey.registration_start")(function* ({ payload, }) {
2077
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.registration_start");
2078
+ return yield* dependencies.passkeyOptions
2079
+ .startRegistration(passkeyRegistrationStartInput(payload, dependencies))
2080
+ .pipe(Effect.mapError(() => passkeyInternalError("Failed to start passkey registration")));
2081
+ });
2082
+ export const makePasskeyRegistrationFinishHandler = (dependencies) => Effect.fn("auth.http.passkey.registration_finish")(function* ({ payload, }) {
2083
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.registration_finish");
2084
+ const finished = yield* dependencies.passkeyVerification
2085
+ .finishRegistration(passkeyRegistrationFinishInput(payload, dependencies))
2086
+ .pipe(Effect.mapError(passkeyVerificationHttpError));
2087
+ return { credentialId: finished.credential.credentialId };
2088
+ });
2089
+ export const makePasskeyAuthenticationStartHandler = (dependencies) => Effect.fn("auth.http.passkey.authentication_start")(function* ({ payload, }) {
2090
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.authentication_start");
2091
+ return yield* dependencies.passkeyOptions
2092
+ .startAuthentication(passkeyAuthenticationStartInput(payload, dependencies))
2093
+ .pipe(Effect.mapError(() => passkeyInternalError("Failed to start passkey authentication")));
2094
+ });
2095
+ export const makePasskeyAuthenticationFinishHandler = (dependencies) => Effect.fn("auth.http.passkey.authentication_finish")(function* ({ payload, request, }) {
2096
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.authentication_finish");
2097
+ const finished = yield* dependencies.passkeyVerification
2098
+ .finishAuthentication(passkeyAuthenticationFinishInput(payload, dependencies))
2099
+ .pipe(Effect.mapError(passkeyVerificationHttpError));
2100
+ const session = yield* dependencies.sessions
2101
+ .create(dependencies.makeSessionInput({
2102
+ finished,
2103
+ payload,
2104
+ ...(request === undefined ? {} : { request }),
2105
+ }))
2106
+ .pipe(Effect.mapError(() => passkeyInternalError("Failed to create passkey session")));
2107
+ return yield* dependencies.authHttp.commitAuthenticatedSession(session);
2108
+ });
2109
+ export const makePasskeyCredentialListHandler = (dependencies) => Effect.fn("auth.http.passkey.credential_list")(function* ({ request, }) {
2110
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.credential_list");
2111
+ const current = yield* readRequiredSession(dependencies, request);
2112
+ const credentials = yield* dependencies.passkeyCredentialManagement
2113
+ .listForUser({ userId: current.currentSession.userId })
2114
+ .pipe(Effect.mapError(() => passkeyInternalError("Failed to list passkey credentials")));
2115
+ return {
2116
+ credentials: credentials.map(passkeyCredentialInfoHttpBody),
2117
+ };
2118
+ });
2119
+ export const makePasskeyCredentialRevokeHandler = (dependencies) => Effect.fn("auth.http.passkey.credential_revoke")(function* ({ payload, request, }) {
2120
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "passkey.credential_revoke");
2121
+ const current = yield* readRequiredSession(dependencies, request);
2122
+ yield* dependencies.passkeyCredentialManagement
2123
+ .revokeForUser(passkeyCredentialRevokeInput(current.currentSession.userId, payload))
2124
+ .pipe(Effect.mapError(passkeyCredentialManagementHttpError));
2125
+ return HttpServerResponse.empty({ status: 204 });
2126
+ });
2127
+ export const makeTotpEnrollmentStartHandler = (dependencies) => Effect.fn("auth.http.totp.enrollment_start")(function* ({ payload, request, }) {
2128
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "totp.enrollment_start");
2129
+ const current = yield* readRequiredSession(dependencies, request);
2130
+ const started = yield* dependencies.totpFactorManagement
2131
+ .startEnrollment(totpEnrollmentStartInput(current.currentSession.userId, payload, dependencies))
2132
+ .pipe(Effect.mapError(totpFactorManagementHttpError));
2133
+ return totpEnrollmentStartedHttpBody(started);
2134
+ });
2135
+ export const makeTotpEnrollmentConfirmHandler = (dependencies) => Effect.fn("auth.http.totp.enrollment_confirm")(function* ({ payload, request, }) {
2136
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "totp.enrollment_confirm");
2137
+ const current = yield* readRequiredSession(dependencies, request);
2138
+ const confirmed = yield* dependencies.totpFactorManagement
2139
+ .confirmEnrollment(totpEnrollmentConfirmInput(current.currentSession.userId, payload, dependencies))
2140
+ .pipe(Effect.mapError(totpFactorManagementHttpError));
2141
+ return totpFactorInfoHttpBody(confirmed);
2142
+ });
2143
+ export const makeTotpVerifyHandler = (dependencies) => Effect.fn("auth.http.totp.verify")(function* ({ payload, request, }) {
2144
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "totp.verify");
2145
+ const current = yield* readRequiredSession(dependencies, request);
2146
+ const result = yield* dependencies.totpFactorManagement
2147
+ .verifyForUser(totpVerifyInput(current.currentSession.userId, payload, dependencies))
2148
+ .pipe(Effect.mapError(() => totpInternalError("Failed to verify TOTP factor")));
2149
+ return totpVerifyResultHttpBody(result);
2150
+ });
2151
+ export const makeTotpFactorListHandler = (dependencies) => Effect.fn("auth.http.totp.factor_list")(function* ({ request, }) {
2152
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "totp.factor_list");
2153
+ const current = yield* readRequiredSession(dependencies, request);
2154
+ const factors = yield* dependencies.totpFactorManagement
2155
+ .listForUser({ userId: current.currentSession.userId })
2156
+ .pipe(Effect.mapError(() => totpInternalError("Failed to list TOTP factors")));
2157
+ return { factors: factors.map(totpFactorInfoHttpBody) };
2158
+ });
2159
+ export const makeTotpFactorRevokeHandler = (dependencies) => Effect.fn("auth.http.totp.factor_revoke")(function* ({ payload, request, }) {
2160
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "totp.factor_revoke");
2161
+ const current = yield* readRequiredSession(dependencies, request);
2162
+ yield* dependencies.totpFactorManagement
2163
+ .revokeForUser(totpFactorRevokeInput(current.currentSession.userId, payload))
2164
+ .pipe(Effect.mapError(totpFactorManagementHttpError));
2165
+ return HttpServerResponse.empty({ status: 204 });
2166
+ });
2167
+ export const makeRecoveryCodeGenerateHandler = (dependencies) => Effect.fn("auth.http.recovery_code.generate")(function* ({ payload, request, }) {
2168
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "recovery_code.generate");
2169
+ const current = yield* readRequiredSession(dependencies, request);
2170
+ const generated = yield* dependencies.recoveryCodeManagement
2171
+ .generateForUser(recoveryCodeGenerateInput(current.currentSession.userId, payload, dependencies))
2172
+ .pipe(Effect.mapError(recoveryCodeManagementHttpError));
2173
+ return recoveryCodesGeneratedHttpBody(generated);
2174
+ });
2175
+ export const makeRecoveryCodeVerifyHandler = (dependencies) => Effect.fn("auth.http.recovery_code.verify")(function* ({ payload, request, }) {
2176
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "recovery_code.verify");
2177
+ const current = yield* readRequiredSession(dependencies, request);
2178
+ const result = yield* dependencies.recoveryCodeManagement
2179
+ .verifyForUser(recoveryCodeVerifyInput(current.currentSession.userId, payload))
2180
+ .pipe(Effect.mapError(() => recoveryCodeInternalError("Failed to verify recovery code")));
2181
+ return recoveryCodeVerifyResultHttpBody(result);
2182
+ });
2183
+ export const makeRecoveryCodeListHandler = (dependencies) => Effect.fn("auth.http.recovery_code.list")(function* ({ request, }) {
2184
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "recovery_code.list");
2185
+ const current = yield* readRequiredSession(dependencies, request);
2186
+ const codes = yield* dependencies.recoveryCodeManagement
2187
+ .listForUser({ userId: current.currentSession.userId })
2188
+ .pipe(Effect.mapError(() => recoveryCodeInternalError("Failed to list recovery codes")));
2189
+ return { codes: codes.map(recoveryCodeInfoHttpBody) };
2190
+ });
2191
+ export const makeRecoveryCodeRevokeHandler = (dependencies) => Effect.fn("auth.http.recovery_code.revoke")(function* ({ payload, request, }) {
2192
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "recovery_code.revoke");
2193
+ const current = yield* readRequiredSession(dependencies, request);
2194
+ yield* dependencies.recoveryCodeManagement
2195
+ .revokeForUser(recoveryCodeRevokeInput(current.currentSession.userId, payload))
2196
+ .pipe(Effect.mapError(recoveryCodeManagementHttpError));
2197
+ return HttpServerResponse.empty({ status: 204 });
2198
+ });
2199
+ export const makeApiKeyCreateHandler = (dependencies) => Effect.fn("auth.http.api_key.create")(function* ({ payload, request, }) {
2200
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "api_key.create");
2201
+ const current = yield* readRequiredSession(dependencies, request);
2202
+ const created = yield* dependencies.apiKeyManagement
2203
+ .createForUser(apiKeyCreateInput(current.currentSession.userId, payload))
2204
+ .pipe(Effect.mapError(apiKeyManagementHttpError));
2205
+ return apiKeyCreatedHttpBody(created);
2206
+ });
2207
+ export const makeApiKeyListHandler = (dependencies) => Effect.fn("auth.http.api_key.list")(function* ({ request, }) {
2208
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "api_key.list");
2209
+ const current = yield* readRequiredSession(dependencies, request);
2210
+ const keys = yield* dependencies.apiKeyManagement
2211
+ .listForUser({ userId: current.currentSession.userId })
2212
+ .pipe(Effect.mapError(() => apiKeyInternalError("Failed to list API keys")));
2213
+ return { keys: keys.map(apiKeyInfoHttpBody) };
2214
+ });
2215
+ export const makeApiKeyRevokeHandler = (dependencies) => Effect.fn("auth.http.api_key.revoke")(function* ({ payload, request, }) {
2216
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "api_key.revoke");
2217
+ const current = yield* readRequiredSession(dependencies, request);
2218
+ yield* dependencies.apiKeyManagement
2219
+ .revokeForUser(apiKeyRevokeInput(current.currentSession.userId, payload))
2220
+ .pipe(Effect.mapError(apiKeyManagementHttpError));
2221
+ return HttpServerResponse.empty({ status: 204 });
2222
+ });
2223
+ export const makeRefreshTokenRefreshHandler = (dependencies) => Effect.fn("auth.http.refresh_token.refresh")(function* ({ payload, }) {
2224
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "refresh_token.refresh");
2225
+ const now = yield* currentUnixMillis;
2226
+ const expiresAt = dependencies.refreshTokenExpiresAt({ now });
2227
+ const rotated = yield* dependencies.refreshTokenManagement
2228
+ .rotate(refreshTokenRefreshInput(payload, now, expiresAt))
2229
+ .pipe(Effect.mapError(() => refreshTokenInternalError("Failed to rotate refresh token")));
2230
+ switch (rotated._tag) {
2231
+ case "Invalid": {
2232
+ return yield* refreshTokenInvalidCredentials();
2233
+ }
2234
+ case "ReuseDetected": {
2235
+ return yield* refreshTokenInvalidCredentials("Refresh token reuse detected");
2236
+ }
2237
+ case "Rotated": {
2238
+ const accessToken = yield* dependencies.jwtIssuer
2239
+ .issue(dependencies.accessToken({
2240
+ now,
2241
+ refreshToken: rotated.refreshToken,
2242
+ previousToken: rotated.previousToken,
2243
+ }))
2244
+ .pipe(Effect.mapError(() => refreshTokenInternalError("Failed to issue access token")));
2245
+ return refreshTokenRefreshedHttpBody({
2246
+ accessToken,
2247
+ refreshToken: Redacted.value(rotated.token),
2248
+ refreshTokenRecord: rotated.refreshToken,
2249
+ });
2250
+ }
2251
+ }
2252
+ });
2253
+ export const makeJwtIntrospectHandler = (dependencies) => Effect.fn("auth.http.jwt.introspect")(function* ({ payload, }) {
2254
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "jwt.introspect");
2255
+ const result = yield* dependencies.jwtRevocation
2256
+ .introspect(jwtIntrospectInput(payload, dependencies))
2257
+ .pipe(Effect.mapError(() => jwtInternalError("Failed to introspect JWT access token")));
2258
+ return jwtIntrospectionHttpBody(result);
2259
+ });
2260
+ export const makeJwtRevokeHandler = (dependencies) => Effect.fn("auth.http.jwt.revoke")(function* ({ payload }) {
2261
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "jwt.revoke");
2262
+ yield* dependencies.jwtRevocation
2263
+ .revokeJwtId(jwtRevokeInput(payload))
2264
+ .pipe(Effect.mapError(jwtRevocationHttpError));
2265
+ return HttpServerResponse.empty({ status: 204 });
2266
+ });
2267
+ export const makeJwtJwksHandler = (dependencies) => Effect.fn("auth.http.jwt.jwks")(function* (_) {
2268
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "jwt.jwks");
2269
+ const document = yield* dependencies.jwks.document().pipe(Effect.mapError(() => jwtInternalError("Failed to load JWT JWKS document")));
2270
+ return jwtJwksHttpBody(document);
2271
+ });
2272
+ export const makeOidcDiscoveryMetadataHandler = (dependencies) => Effect.fn("auth.http.oidc.discovery_metadata")(function* (_) {
2273
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "oidc.discovery_metadata");
2274
+ return yield* dependencies.metadata.load().pipe(Effect.mapError(() => jwtInternalError("Failed to load OIDC discovery metadata")));
2275
+ });
2276
+ export const makeMfaOptionsHandler = (dependencies) => Effect.fn("auth.http.mfa.options")(function* ({ payload, }) {
2277
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.options");
2278
+ const pending = yield* dependencies.authFlowState
2279
+ .inspect(payload.flowId)
2280
+ .pipe(Effect.mapError(() => mfaBadRequest()));
2281
+ const factors = [];
2282
+ if (dependencies.totpFactorManagement !== undefined) {
2283
+ const totpFactors = yield* dependencies.totpFactorManagement
2284
+ .listForUser({ userId: pending.userId })
2285
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to list MFA options")));
2286
+ if (totpFactors.length > 0) {
2287
+ factors.push({ type: "totp" });
2288
+ }
2289
+ }
2290
+ if (dependencies.recoveryCodeManagement !== undefined) {
2291
+ const recoveryCodes = yield* dependencies.recoveryCodeManagement
2292
+ .listForUser({ userId: pending.userId })
2293
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to list MFA options")));
2294
+ if (recoveryCodes.length > 0) {
2295
+ factors.push({ type: "backup-code" });
2296
+ }
2297
+ }
2298
+ if (dependencies.passkeyCredentialManagement !== undefined) {
2299
+ const credentials = yield* dependencies.passkeyCredentialManagement
2300
+ .listForUser({ userId: pending.userId })
2301
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to list MFA options")));
2302
+ if (credentials.length > 0) {
2303
+ factors.push({ type: "passkey" });
2304
+ }
2305
+ }
2306
+ return { factors };
2307
+ });
2308
+ export const makeTotpMfaVerifyHandler = (dependencies) => Effect.fn("auth.http.mfa.totp_verify")(function* ({ payload, }) {
2309
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.totp_verify");
2310
+ const verified = yield* dependencies.totpFactorManagement
2311
+ .verifyForUser(totpMfaVerifyInput(payload, dependencies))
2312
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to verify TOTP MFA factor")));
2313
+ if (!verified.valid) {
2314
+ return yield* mfaInvalidCredentials();
2315
+ }
2316
+ const result = yield* dependencies.authFlow
2317
+ .completeMfa({
2318
+ flowId: payload.flowId,
2319
+ userId: payload.userId,
2320
+ method: "totp",
2321
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
2322
+ })
2323
+ .pipe(Effect.mapError(authFlowMfaHttpError));
2324
+ if (result._tag === "PolicyDenied") {
2325
+ return yield* mfaPolicyDenied(result.reason);
2326
+ }
2327
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session);
2328
+ });
2329
+ export const makeTotpMfaVerifyForFlowHandler = (dependencies) => Effect.fn("auth.http.mfa.totp_verify_for_flow")(function* ({ payload, }) {
2330
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.totp_verify_for_flow");
2331
+ const pending = yield* dependencies.authFlowState
2332
+ .inspect(payload.flowId)
2333
+ .pipe(Effect.mapError(() => mfaBadRequest()));
2334
+ const verified = yield* dependencies.totpFactorManagement
2335
+ .verifyForUser(totpMfaVerifyForFlowInput(pending.userId, payload, dependencies))
2336
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to verify TOTP MFA factor")));
2337
+ if (!verified.valid) {
2338
+ return yield* mfaInvalidCredentials();
2339
+ }
2340
+ const result = yield* dependencies.authFlow
2341
+ .completeMfa({
2342
+ flowId: payload.flowId,
2343
+ userId: pending.userId,
2344
+ method: "totp",
2345
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
2346
+ })
2347
+ .pipe(Effect.mapError(authFlowMfaHttpError));
2348
+ if (result._tag === "PolicyDenied") {
2349
+ return yield* mfaPolicyDenied(result.reason);
2350
+ }
2351
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session);
2352
+ });
2353
+ export const makeRecoveryCodeMfaVerifyHandler = (dependencies) => Effect.fn("auth.http.mfa.recovery_code_verify")(function* ({ payload, }) {
2354
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.recovery_code_verify");
2355
+ const verified = yield* dependencies.recoveryCodeManagement
2356
+ .verifyForUser(recoveryCodeMfaVerifyInput(payload))
2357
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to verify recovery code MFA factor")));
2358
+ if (!verified.valid) {
2359
+ return yield* mfaInvalidCredentials();
2360
+ }
2361
+ const result = yield* dependencies.authFlow
2362
+ .completeMfa({
2363
+ flowId: payload.flowId,
2364
+ userId: payload.userId,
2365
+ method: "backup-code",
2366
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
2367
+ })
2368
+ .pipe(Effect.mapError(authFlowMfaHttpError));
2369
+ if (result._tag === "PolicyDenied") {
2370
+ return yield* mfaPolicyDenied(result.reason);
2371
+ }
2372
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session);
2373
+ });
2374
+ export const makeRecoveryCodeMfaVerifyForFlowHandler = (dependencies) => Effect.fn("auth.http.mfa.recovery_code_verify_for_flow")(function* ({ payload, }) {
2375
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.recovery_code_verify_for_flow");
2376
+ const pending = yield* dependencies.authFlowState
2377
+ .inspect(payload.flowId)
2378
+ .pipe(Effect.mapError(() => mfaBadRequest()));
2379
+ const verified = yield* dependencies.recoveryCodeManagement
2380
+ .verifyForUser(recoveryCodeMfaVerifyForFlowInput(pending.userId, payload))
2381
+ .pipe(Effect.mapError(() => mfaInternalError("Failed to verify recovery code MFA factor")));
2382
+ if (!verified.valid) {
2383
+ return yield* mfaInvalidCredentials();
2384
+ }
2385
+ const result = yield* dependencies.authFlow
2386
+ .completeMfa({
2387
+ flowId: payload.flowId,
2388
+ userId: pending.userId,
2389
+ method: "backup-code",
2390
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
2391
+ })
2392
+ .pipe(Effect.mapError(authFlowMfaHttpError));
2393
+ if (result._tag === "PolicyDenied") {
2394
+ return yield* mfaPolicyDenied(result.reason);
2395
+ }
2396
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session);
2397
+ });
2398
+ export const makePasskeyMfaStartHandler = (dependencies) => Effect.fn("auth.http.mfa.passkey_start")(function* ({ payload, }) {
2399
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.passkey_start");
2400
+ const pending = yield* dependencies.authFlowState
2401
+ .inspect(payload.flowId)
2402
+ .pipe(Effect.mapError(() => mfaBadRequest()));
2403
+ return yield* dependencies.passkeyOptions
2404
+ .startAuthentication(passkeyMfaStartInput(pending.userId, payload, dependencies))
2405
+ .pipe(Effect.mapError(() => passkeyInternalError("Failed to start passkey MFA authentication")));
2406
+ });
2407
+ export const makePasskeyMfaVerifyHandler = (dependencies) => Effect.fn("auth.http.mfa.passkey_verify")(function* ({ payload, }) {
2408
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "mfa.passkey_verify");
2409
+ const finished = yield* dependencies.passkeyVerification
2410
+ .finishAuthentication(passkeyMfaVerifyInput(payload, dependencies))
2411
+ .pipe(Effect.mapError(passkeyVerificationHttpError));
2412
+ const result = yield* dependencies.authFlow
2413
+ .completeMfa({
2414
+ flowId: payload.flowId,
2415
+ userId: finished.userId,
2416
+ method: "passkey",
2417
+ ...(payload.metadata === undefined ? {} : { metadata: payload.metadata }),
2418
+ })
2419
+ .pipe(Effect.mapError(authFlowMfaHttpError));
2420
+ if (result._tag === "PolicyDenied") {
2421
+ return yield* mfaPolicyDenied(result.reason);
2422
+ }
2423
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session);
2424
+ });
2425
+ const upgradeStepUpSession = (dependencies, current, method) => upgradeCurrentSession({ method, reason: "step_up" }).pipe(Effect.provideService(CurrentSession, CurrentSession.make(current.currentSession)), Effect.provideService(Sessions, dependencies.sessions), Effect.map(stepUpAuthenticatedHttpBody), Effect.mapError(() => stepUpInternalError("Failed to upgrade current session")));
2426
+ export const makeStepUpOptionsHandler = (dependencies) => Effect.fn("auth.http.step_up.options")(function* ({ request, }) {
2427
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "step_up.options");
2428
+ const current = yield* readRequiredSession(dependencies, request);
2429
+ const { userId } = current.currentSession;
2430
+ const factors = [];
2431
+ if (dependencies.totpFactorManagement !== undefined) {
2432
+ const totpFactors = yield* dependencies.totpFactorManagement
2433
+ .listForUser({ userId })
2434
+ .pipe(Effect.mapError(() => stepUpInternalError("Failed to list step-up options")));
2435
+ if (totpFactors.length > 0) {
2436
+ factors.push({ type: "totp" });
2437
+ }
2438
+ }
2439
+ if (dependencies.recoveryCodeManagement !== undefined) {
2440
+ const recoveryCodes = yield* dependencies.recoveryCodeManagement
2441
+ .listForUser({ userId })
2442
+ .pipe(Effect.mapError(() => stepUpInternalError("Failed to list step-up options")));
2443
+ if (recoveryCodes.length > 0) {
2444
+ factors.push({ type: "backup-code" });
2445
+ }
2446
+ }
2447
+ if (dependencies.passkeyCredentialManagement !== undefined) {
2448
+ const credentials = yield* dependencies.passkeyCredentialManagement
2449
+ .listForUser({ userId })
2450
+ .pipe(Effect.mapError(() => stepUpInternalError("Failed to list step-up options")));
2451
+ if (credentials.length > 0) {
2452
+ factors.push({ type: "passkey" });
2453
+ }
2454
+ }
2455
+ return { factors };
2456
+ });
2457
+ export const makeStepUpTotpVerifyHandler = (dependencies) => Effect.fn("auth.http.step_up.totp_verify")(function* ({ payload, request, }) {
2458
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "step_up.totp_verify");
2459
+ const current = yield* readRequiredSession(dependencies, request);
2460
+ const verified = yield* dependencies.totpFactorManagement
2461
+ .verifyForUser(stepUpTotpVerifyInput(current.currentSession.userId, payload, dependencies))
2462
+ .pipe(Effect.mapError(() => stepUpInternalError("Failed to verify TOTP step-up factor")));
2463
+ if (!verified.valid) {
2464
+ return yield* stepUpInvalidCredentials();
2465
+ }
2466
+ return yield* upgradeStepUpSession(dependencies, current, "totp");
2467
+ });
2468
+ export const makeStepUpRecoveryCodeVerifyHandler = (dependencies) => Effect.fn("auth.http.step_up.recovery_code_verify")(function* ({ payload, request, }) {
2469
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "step_up.recovery_code_verify");
2470
+ const current = yield* readRequiredSession(dependencies, request);
2471
+ const verified = yield* dependencies.recoveryCodeManagement
2472
+ .verifyForUser(stepUpRecoveryCodeVerifyInput(current.currentSession.userId, payload))
2473
+ .pipe(Effect.mapError(() => stepUpInternalError("Failed to verify recovery-code step-up factor")));
2474
+ if (!verified.valid) {
2475
+ return yield* stepUpInvalidCredentials();
2476
+ }
2477
+ return yield* upgradeStepUpSession(dependencies, current, "backup_code");
2478
+ });
2479
+ export const makeStepUpPasskeyStartHandler = (dependencies) => Effect.fn("auth.http.step_up.passkey_start")(function* ({ payload, request, }) {
2480
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "step_up.passkey_start");
2481
+ const current = yield* readRequiredSession(dependencies, request);
2482
+ return yield* dependencies.passkeyOptions
2483
+ .startAuthentication(stepUpPasskeyStartInput(current.currentSession.userId, payload, dependencies))
2484
+ .pipe(Effect.mapError((error) => error.cause === undefined
2485
+ ? stepUpBadRequest()
2486
+ : stepUpInternalError("Failed to start passkey step-up")));
2487
+ });
2488
+ export const makeStepUpPasskeyVerifyHandler = (dependencies) => Effect.fn("auth.http.step_up.passkey_verify")(function* ({ payload, request, }) {
2489
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "step_up.passkey_verify");
2490
+ const current = yield* readRequiredSession(dependencies, request);
2491
+ const finished = yield* dependencies.passkeyVerification
2492
+ .finishAuthentication(stepUpPasskeyVerifyInput(current.currentSession.userId, payload, dependencies))
2493
+ .pipe(Effect.mapError(passkeyVerificationHttpError));
2494
+ if (finished.userId !== current.currentSession.userId) {
2495
+ return yield* stepUpPolicyDenied("Passkey belongs to a different user");
2496
+ }
2497
+ return yield* upgradeStepUpSession(dependencies, current, "passkey");
2498
+ });
2499
+ export const makeLoginApprovalApproveHandler = (dependencies) => Effect.fn("auth.http.login_approval.approve")(function* ({ payload, request, }) {
2500
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "login_approval.approve");
2501
+ const input = loginApprovalApproveInput(payload);
2502
+ const approval = yield* dependencies.loginApproval
2503
+ .verify(input.approval)
2504
+ .pipe(Effect.mapError(() => loginApprovalBadRequest()));
2505
+ const approvedFlowId = metadataString(approval.metadata, "flowId");
2506
+ if (approvedFlowId !== input.flowId) {
2507
+ return yield* loginApprovalBadRequest();
2508
+ }
2509
+ if (approval.sessionBinding === "none") {
2510
+ return yield* loginApprovalNoSessionBindingDenied();
2511
+ }
2512
+ const sameDeviceSecret = approval.sameDeviceRequired
2513
+ ? yield* dependencies.loginApprovalPendingCookie
2514
+ .read(new Request("http://localhost", { headers: request.headers }))
2515
+ .pipe(Effect.flatMap((secret) => Option.isSome(secret)
2516
+ ? Effect.succeed(secret.value)
2517
+ : Effect.fail(loginApprovalSameDeviceDenied())))
2518
+ : undefined;
2519
+ const consumed = yield* dependencies.authFlowState
2520
+ .consume(input.flowId, sameDeviceSecret)
2521
+ .pipe(Effect.mapError(() => approval.sameDeviceRequired
2522
+ ? loginApprovalSameDeviceDenied()
2523
+ : loginApprovalBadRequest()));
2524
+ if (consumed.userId !== approval.userId) {
2525
+ return yield* loginApprovalBadRequest();
2526
+ }
2527
+ if (approval.markEmailVerified === true) {
2528
+ const updated = yield* dependencies.users
2529
+ .markEmailVerified({
2530
+ userId: approval.userId,
2531
+ updatedAt: yield* currentUnixMillis,
2532
+ })
2533
+ .pipe(Effect.mapError(() => passwordInternalError("Failed to mark email verified")));
2534
+ if (Option.isNone(updated)) {
2535
+ return yield* loginApprovalBadRequest();
2536
+ }
2537
+ }
2538
+ const result = yield* dependencies.authFlow
2539
+ .complete(consumed)
2540
+ .pipe(Effect.mapError(() => passwordInternalError("Failed to complete login approval")));
2541
+ const setCookies = yield* trustedDeviceSetCookies({
2542
+ trustedDevice: dependencies.trustedDevice,
2543
+ trustedDeviceCookie: dependencies.trustedDeviceCookie,
2544
+ userId: consumed.userId,
2545
+ rememberDevice: input.rememberDevice,
2546
+ });
2547
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session, { setCookies });
2548
+ });
2549
+ export const makeLoginApprovalStatusHandler = (dependencies) => Effect.fn("auth.http.login_approval.status")(function* ({ payload, }) {
2550
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "login_approval.status");
2551
+ if (dependencies.loginApprovalReview === undefined) {
2552
+ return yield* loginApprovalReviewNotConfigured();
2553
+ }
2554
+ const input = loginApprovalStatusInput(payload);
2555
+ const recordOption = yield* dependencies.loginApprovalReview
2556
+ .status({ approvalChallengeId: input.approvalChallengeId })
2557
+ .pipe(Effect.mapError(() => passwordInternalError("Failed to load login approval review")));
2558
+ if (Option.isNone(recordOption)) {
2559
+ return yield* loginApprovalBadRequest();
2560
+ }
2561
+ const record = recordOption.value;
2562
+ if (record.flowId !== input.flowId) {
2563
+ return yield* loginApprovalBadRequest();
2564
+ }
2565
+ const now = yield* currentUnixMillis;
2566
+ const status = Number(record.expiresAt) <= Number(now)
2567
+ ? "expired"
2568
+ : record.status;
2569
+ return {
2570
+ status,
2571
+ expiresAt: record.expiresAt,
2572
+ };
2573
+ });
2574
+ export const makeLoginApprovalFinalizeHandler = (dependencies) => Effect.fn("auth.http.login_approval.finalize")(function* ({ payload, request, }) {
2575
+ yield* Effect.annotateCurrentSpan("auth.http.endpoint", "login_approval.finalize");
2576
+ if (dependencies.loginApprovalFinalize === undefined) {
2577
+ return yield* loginApprovalFinalizeNotConfigured();
2578
+ }
2579
+ const input = loginApprovalFinalizeInput(payload);
2580
+ const sameDeviceSecret = yield* dependencies.loginApprovalPendingCookie.read(new Request("http://localhost", { headers: request.headers }));
2581
+ const result = yield* dependencies.loginApprovalFinalize
2582
+ .complete({
2583
+ flowId: input.flowId,
2584
+ approvalChallengeId: input.approvalChallengeId,
2585
+ ...(Option.isSome(sameDeviceSecret)
2586
+ ? { sameDeviceSecret: sameDeviceSecret.value }
2587
+ : {}),
2588
+ })
2589
+ .pipe(Effect.mapError((error) => error._tag === "AuthFlowStateError"
2590
+ ? loginApprovalSameDeviceDenied()
2591
+ : passwordInternalError("Failed to finalize login approval")));
2592
+ if (result._tag === "PolicyDenied") {
2593
+ return yield* loginApprovalPolicyDenied(result.reason);
2594
+ }
2595
+ const setCookies = yield* trustedDeviceSetCookies({
2596
+ trustedDevice: dependencies.trustedDevice,
2597
+ trustedDeviceCookie: dependencies.trustedDeviceCookie,
2598
+ userId: result.session.userId,
2599
+ rememberDevice: input.rememberDevice,
2600
+ });
2601
+ return yield* dependencies.authHttp.commitAuthenticatedSession(result.session, { setCookies });
2602
+ });
2603
+ export class PasswordApi extends HttpApiGroup.make("password")
2604
+ .add(passwordSignInEndpoint.middleware(AuthRateLimitMiddleware), passwordSignUpEndpoint.middleware(AuthRateLimitMiddleware), passwordResetStartEndpoint.middleware(AuthRateLimitMiddleware), passwordResetVerifyEndpoint.middleware(AuthRateLimitMiddleware), passwordSetEndpoint.middleware(AuthOriginCheckMiddleware), passwordChangeEndpoint.middleware(AuthOriginCheckMiddleware))
2605
+ .prefix("/auth/password")
2606
+ .middleware(AuthSchemaErrorMiddleware)
2607
+ .middleware(AuthOriginCheckMiddleware) {
2608
+ }
2609
+ export class SessionApi extends HttpApiGroup.make("session")
2610
+ .add(currentSessionEndpoint, refreshSessionEndpoint.middleware(AuthOriginCheckMiddleware), logoutEndpoint.middleware(AuthOriginCheckMiddleware), listSessionsEndpoint, revokeSessionEndpoint.middleware(AuthOriginCheckMiddleware), revokeOtherSessionsEndpoint.middleware(AuthOriginCheckMiddleware))
2611
+ .prefix("/auth") {
2612
+ }
2613
+ export class AdminSessionApi extends HttpApiGroup.make("adminSession")
2614
+ .add(adminSessionListEndpoint, adminSessionRevokeEndpoint, adminSessionRevokeAllEndpoint)
2615
+ .prefix("/auth/admin/sessions")
2616
+ .middleware(AuthSchemaErrorMiddleware)
2617
+ .middleware(AuthOriginCheckMiddleware) {
2618
+ }
2619
+ export class AdminSessionHttpApi extends HttpApi.make("AdminSessionHttpApi").add(AdminSessionApi) {
2620
+ }
2621
+ export class EmailVerificationApi extends HttpApiGroup.make("emailVerification")
2622
+ .add(emailVerificationStartEndpoint.middleware(AuthRateLimitMiddleware), emailVerificationVerifyEndpoint)
2623
+ .prefix("/auth/email-verification")
2624
+ .middleware(AuthSchemaErrorMiddleware)
2625
+ .middleware(AuthOriginCheckMiddleware) {
2626
+ }
2627
+ export class EmailOtpApi extends HttpApiGroup.make("emailOtp")
2628
+ .add(emailOtpStartEndpoint.middleware(AuthRateLimitMiddleware), emailOtpVerifyEndpoint.middleware(AuthRateLimitMiddleware))
2629
+ .prefix("/auth/email-otp")
2630
+ .middleware(AuthSchemaErrorMiddleware)
2631
+ .middleware(AuthOriginCheckMiddleware) {
2632
+ }
2633
+ export class MagicLinkApi extends HttpApiGroup.make("magicLink")
2634
+ .add(magicLinkStartEndpoint.middleware(AuthRateLimitMiddleware), magicLinkVerifyEndpoint.middleware(AuthRateLimitMiddleware))
2635
+ .prefix("/auth/magic-link")
2636
+ .middleware(AuthSchemaErrorMiddleware)
2637
+ .middleware(AuthOriginCheckMiddleware) {
2638
+ }
2639
+ export class OAuthApi extends HttpApiGroup.make("oauth")
2640
+ .add(oauthAuthorizationStartEndpoint, oauthAccountUnlinkEndpoint, oauthLinkConfirmationStartEndpoint, oauthLinkConfirmationInspectEndpoint, oauthLinkConfirmationConfirmEndpoint)
2641
+ .prefix("/auth/oauth")
2642
+ .middleware(AuthSchemaErrorMiddleware)
2643
+ .middleware(AuthOriginCheckMiddleware) {
2644
+ }
2645
+ export class OAuthTokenApi extends HttpApiGroup.make("oauthToken")
2646
+ .add(oauthTokenEndpoint, oauthTokenIntrospectionEndpoint, oauthTokenRevocationEndpoint)
2647
+ .prefix("/auth/oauth")
2648
+ .middleware(AuthSchemaErrorMiddleware) {
2649
+ }
2650
+ export class OAuthTokenHttpApi extends HttpApi.make("OAuthTokenHttpApi").add(OAuthTokenApi) {
2651
+ }
2652
+ export class OAuthProviderAuthorizationApi extends HttpApiGroup.make("oauthProviderAuthorization")
2653
+ .add(oauthProviderAuthorizeEndpoint)
2654
+ .prefix("/auth/oauth")
2655
+ .middleware(AuthSchemaErrorMiddleware) {
2656
+ }
2657
+ export class OAuthProviderAuthorizationHttpApi extends HttpApi.make("OAuthProviderAuthorizationHttpApi").add(OAuthProviderAuthorizationApi) {
2658
+ }
2659
+ export class LoginApprovalApi extends HttpApiGroup.make("loginApproval")
2660
+ .add(loginApprovalApproveEndpoint, loginApprovalStatusEndpoint, loginApprovalFinalizeEndpoint)
2661
+ .prefix("/auth/login-approval")
2662
+ .middleware(AuthSchemaErrorMiddleware)
2663
+ .middleware(AuthOriginCheckMiddleware) {
2664
+ }
2665
+ export class MfaApi extends HttpApiGroup.make("mfa")
2666
+ .add(mfaOptionsEndpoint, totpMfaVerifyEndpoint, totpMfaVerifyForFlowEndpoint, recoveryCodeMfaVerifyEndpoint, recoveryCodeMfaVerifyForFlowEndpoint, passkeyMfaStartEndpoint, passkeyMfaVerifyEndpoint)
2667
+ .prefix("/auth/mfa")
2668
+ .middleware(AuthSchemaErrorMiddleware)
2669
+ .middleware(AuthOriginCheckMiddleware) {
2670
+ }
2671
+ export class StepUpApi extends HttpApiGroup.make("stepUp")
2672
+ .add(stepUpOptionsEndpoint, stepUpTotpVerifyEndpoint, stepUpRecoveryCodeVerifyEndpoint, stepUpPasskeyStartEndpoint, stepUpPasskeyVerifyEndpoint)
2673
+ .prefix("/auth/step-up")
2674
+ .middleware(AuthSchemaErrorMiddleware)
2675
+ .middleware(AuthOriginCheckMiddleware) {
2676
+ }
2677
+ export class ApiKeyApi extends HttpApiGroup.make("apiKey")
2678
+ .add(apiKeyCreateEndpoint, apiKeyListEndpoint, apiKeyRevokeEndpoint)
2679
+ .prefix("/auth/api-keys")
2680
+ .middleware(AuthSchemaErrorMiddleware)
2681
+ .middleware(AuthOriginCheckMiddleware) {
2682
+ }
2683
+ export class RefreshTokenApi extends HttpApiGroup.make("refreshToken")
2684
+ .add(refreshTokenRefreshEndpoint)
2685
+ .prefix("/auth/token")
2686
+ .middleware(AuthSchemaErrorMiddleware) {
2687
+ }
2688
+ export class JwtApi extends HttpApiGroup.make("jwt")
2689
+ .add(jwtIntrospectEndpoint, jwtRevokeEndpoint)
2690
+ .prefix("/auth/jwt")
2691
+ .middleware(AuthSchemaErrorMiddleware) {
2692
+ }
2693
+ export class JwtDiscoveryApi extends HttpApiGroup.make("jwtDiscovery")
2694
+ .add(jwtJwksEndpoint)
2695
+ .prefix("/.well-known")
2696
+ .middleware(AuthSchemaErrorMiddleware) {
2697
+ }
2698
+ export class JwtDiscoveryHttpApi extends HttpApi.make("JwtDiscoveryHttpApi").add(JwtDiscoveryApi) {
2699
+ }
2700
+ export class OidcDiscoveryApi extends HttpApiGroup.make("oidcDiscovery")
2701
+ .add(oidcDiscoveryMetadataEndpoint)
2702
+ .prefix("/.well-known")
2703
+ .middleware(AuthSchemaErrorMiddleware) {
2704
+ }
2705
+ export class OidcDiscoveryHttpApi extends HttpApi.make("OidcDiscoveryHttpApi").add(OidcDiscoveryApi) {
2706
+ }
2707
+ export class SecurityApi extends HttpApiGroup.make("security")
2708
+ .add(loginNotificationReportEndpoint)
2709
+ .prefix("/auth/security")
2710
+ .middleware(AuthSchemaErrorMiddleware)
2711
+ .middleware(AuthOriginCheckMiddleware) {
2712
+ }
2713
+ export class SecurityTimelineApi extends HttpApiGroup.make("securityTimeline")
2714
+ .add(securityTimelineListEndpoint)
2715
+ .prefix("/auth/security")
2716
+ .middleware(AuthSchemaErrorMiddleware)
2717
+ .middleware(AuthOriginCheckMiddleware) {
2718
+ }
2719
+ export class SecurityTimelineHttpApi extends HttpApi.make("SecurityTimelineHttpApi")
2720
+ .add(SecurityTimelineApi) {
2721
+ }
2722
+ export class AdminSecurityTimelineApi extends HttpApiGroup.make("adminSecurityTimeline")
2723
+ .add(adminSecurityTimelineListEndpoint)
2724
+ .prefix("/auth/admin/security")
2725
+ .middleware(AuthSchemaErrorMiddleware)
2726
+ .middleware(AuthOriginCheckMiddleware) {
2727
+ }
2728
+ export class AdminSecurityTimelineHttpApi extends HttpApi.make("AdminSecurityTimelineHttpApi").add(AdminSecurityTimelineApi) {
2729
+ }
2730
+ export class TrustedDeviceApi extends HttpApiGroup.make("trustedDevice")
2731
+ .add(trustedDeviceListEndpoint, trustedDeviceRevokeEndpoint)
2732
+ .prefix("/auth/trusted-devices")
2733
+ .middleware(AuthSchemaErrorMiddleware)
2734
+ .middleware(AuthOriginCheckMiddleware) {
2735
+ }
2736
+ export class TrustedDeviceHttpApi extends HttpApi.make("TrustedDeviceHttpApi")
2737
+ .add(TrustedDeviceApi) {
2738
+ }
2739
+ export class AdminTrustedDeviceApi extends HttpApiGroup.make("adminTrustedDevice")
2740
+ .add(adminTrustedDeviceListEndpoint, adminTrustedDeviceRevokeEndpoint)
2741
+ .prefix("/auth/admin/trusted-devices")
2742
+ .middleware(AuthSchemaErrorMiddleware)
2743
+ .middleware(AuthOriginCheckMiddleware) {
2744
+ }
2745
+ export class AdminTrustedDeviceHttpApi extends HttpApi.make("AdminTrustedDeviceHttpApi").add(AdminTrustedDeviceApi) {
2746
+ }
2747
+ export class AuthApi extends HttpApi.make("AuthApi")
2748
+ .add(PasswordApi)
2749
+ .add(SessionApi)
2750
+ .add(EmailVerificationApi)
2751
+ .add(EmailOtpApi)
2752
+ .add(MagicLinkApi)
2753
+ .add(LoginApprovalApi)
2754
+ .add(SecurityApi) {
2755
+ }
2756
+ export const PasswordApiLive = HttpApiBuilder.group(AuthApi, "password", Effect.fn("auth.http.password.group")(function* (handlers) {
2757
+ const password = yield* PasswordLogin;
2758
+ const registration = yield* PasswordRegistration;
2759
+ const passwordReset = yield* PasswordReset;
2760
+ const passwordManagement = yield* PasswordManagement;
2761
+ const authHttp = yield* AuthHttp;
2762
+ const emailVerificationFlow = yield* EmailVerificationFlow;
2763
+ const sessions = yield* Sessions;
2764
+ const sessionCookie = yield* SessionCookie;
2765
+ const authApiRateLimit = yield* AuthApiRateLimit;
2766
+ const trustedDeviceCookie = yield* Effect.serviceOption(TrustedDeviceCookie);
2767
+ return handlers
2768
+ .handle("signIn", makePasswordSignInHandler({
2769
+ password,
2770
+ authHttp,
2771
+ emailVerificationFlow,
2772
+ authApiRateLimit,
2773
+ ...(Option.isSome(trustedDeviceCookie)
2774
+ ? { trustedDeviceCookie: trustedDeviceCookie.value }
2775
+ : {}),
2776
+ }))
2777
+ .handle("signUp", makePasswordSignUpHandler({
2778
+ registration,
2779
+ authHttp,
2780
+ emailVerificationFlow,
2781
+ authApiRateLimit,
2782
+ }))
2783
+ .handle("resetStart", makePasswordResetStartHandler({
2784
+ passwordReset,
2785
+ authApiRateLimit,
2786
+ }))
2787
+ .handle("resetVerify", makePasswordResetVerifyHandler({
2788
+ passwordReset,
2789
+ }))
2790
+ .handle("set", makePasswordSetHandler({
2791
+ passwordManagement,
2792
+ sessions,
2793
+ sessionCookie,
2794
+ }))
2795
+ .handle("change", makePasswordChangeHandler({
2796
+ passwordManagement,
2797
+ sessions,
2798
+ sessionCookie,
2799
+ }));
2800
+ }));
2801
+ export const SessionApiLive = HttpApiBuilder.group(AuthApi, "session", Effect.fn("auth.http.session.group")(function* (handlers) {
2802
+ const sessions = yield* Sessions;
2803
+ const sessionCookie = yield* SessionCookie;
2804
+ const authHttp = yield* AuthHttp;
2805
+ return handlers
2806
+ .handle("current", makeCurrentSessionHandler({ sessions, sessionCookie, authHttp }))
2807
+ .handle("refresh", makeRefreshSessionHandler({ sessions, sessionCookie, authHttp }))
2808
+ .handle("logout", makeLogoutHandler({ sessions, sessionCookie, authHttp }))
2809
+ .handle("list", makeListSessionsHandler({ sessions, sessionCookie }))
2810
+ .handle("revoke", makeRevokeSessionHandler({ sessions, sessionCookie, authHttp }))
2811
+ .handle("revokeOthers", makeRevokeOtherSessionsHandler({ sessions, sessionCookie }));
2812
+ }));
2813
+ export const AdminSessionApiLive = HttpApiBuilder.group(AdminSessionHttpApi, "adminSession", Effect.fn("auth.http.admin_session.group")(function* (handlers) {
2814
+ const sessions = yield* Sessions;
2815
+ const sessionCookie = yield* SessionCookie;
2816
+ const authorization = yield* AdminSessionAuthorization;
2817
+ return handlers
2818
+ .handle("list", makeAdminSessionListHandler({ sessions, sessionCookie, authorization }))
2819
+ .handle("revoke", makeAdminSessionRevokeHandler({ sessions, sessionCookie, authorization }))
2820
+ .handle("revokeAll", makeAdminSessionRevokeAllHandler({
2821
+ sessions,
2822
+ sessionCookie,
2823
+ authorization,
2824
+ }));
2825
+ }));
2826
+ export const AdminSessionHttpApiLive = HttpApiBuilder.layer(AdminSessionHttpApi).pipe(Layer.provide(AdminSessionApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2827
+ export const EmailVerificationApiLive = HttpApiBuilder.group(AuthApi, "emailVerification", Effect.fn("auth.http.email_verification.group")(function* (handlers) {
2828
+ const emailVerificationFlow = yield* EmailVerificationFlow;
2829
+ const emailVerification = yield* EmailVerification;
2830
+ const sessions = yield* Sessions;
2831
+ const sessionCookie = yield* SessionCookie;
2832
+ const authApiRateLimit = yield* AuthApiRateLimit;
2833
+ return handlers
2834
+ .handle("start", makeEmailVerificationStartHandler({
2835
+ emailVerificationFlow,
2836
+ authApiRateLimit,
2837
+ }))
2838
+ .handle("verify", makeEmailVerificationVerifyHandler({
2839
+ emailVerification,
2840
+ sessions,
2841
+ sessionCookie,
2842
+ }));
2843
+ }));
2844
+ export const EmailOtpApiLive = HttpApiBuilder.group(AuthApi, "emailOtp", Effect.fn("auth.http.email_otp.group")(function* (handlers) {
2845
+ const emailOtp = yield* EmailOtpLogin;
2846
+ const authHttp = yield* AuthHttp;
2847
+ const authApiRateLimit = yield* AuthApiRateLimit;
2848
+ const trustedDeviceCookie = yield* Effect.serviceOption(TrustedDeviceCookie);
2849
+ return handlers
2850
+ .handle("start", makeEmailOtpStartHandler({ emailOtp, authApiRateLimit }))
2851
+ .handle("verify", makeEmailOtpVerifyHandler({
2852
+ emailOtp,
2853
+ authHttp,
2854
+ ...(Option.isSome(trustedDeviceCookie)
2855
+ ? { trustedDeviceCookie: trustedDeviceCookie.value }
2856
+ : {}),
2857
+ }));
2858
+ }));
2859
+ export const MagicLinkApiLive = HttpApiBuilder.group(AuthApi, "magicLink", Effect.fn("auth.http.magic_link.group")(function* (handlers) {
2860
+ const magicLink = yield* MagicLinkLogin;
2861
+ const authHttp = yield* AuthHttp;
2862
+ const authApiRateLimit = yield* AuthApiRateLimit;
2863
+ const trustedDeviceCookie = yield* Effect.serviceOption(TrustedDeviceCookie);
2864
+ return handlers
2865
+ .handle("start", makeMagicLinkStartHandler({ magicLink, authApiRateLimit }))
2866
+ .handle("verify", makeMagicLinkVerifyHandler({
2867
+ magicLink,
2868
+ authHttp,
2869
+ ...(Option.isSome(trustedDeviceCookie)
2870
+ ? { trustedDeviceCookie: trustedDeviceCookie.value }
2871
+ : {}),
2872
+ }));
2873
+ }));
2874
+ export const LoginApprovalApiLive = HttpApiBuilder.group(AuthApi, "loginApproval", Effect.fn("auth.http.login_approval.group")(function* (handlers) {
2875
+ const loginApproval = yield* LoginApproval;
2876
+ const authFlowState = yield* AuthFlowState;
2877
+ const authFlow = yield* AuthFlow;
2878
+ const users = yield* UserStore;
2879
+ const authHttp = yield* AuthHttp;
2880
+ const loginApprovalReview = yield* Effect.serviceOption(LoginApprovalReview);
2881
+ const loginApprovalFinalize = yield* Effect.serviceOption(LoginApprovalFinalize);
2882
+ const pendingCookieOption = yield* Effect.serviceOption(LoginApprovalPendingCookie);
2883
+ const trustedDevice = yield* Effect.serviceOption(TrustedDevice);
2884
+ const trustedDeviceCookie = yield* Effect.serviceOption(TrustedDeviceCookie);
2885
+ const loginApprovalPendingCookie = Option.isSome(pendingCookieOption)
2886
+ ? pendingCookieOption.value
2887
+ : makeLoginApprovalPendingCookie();
2888
+ return handlers
2889
+ .handle("approve", makeLoginApprovalApproveHandler({
2890
+ loginApproval,
2891
+ authFlowState,
2892
+ authFlow,
2893
+ users,
2894
+ authHttp,
2895
+ loginApprovalPendingCookie,
2896
+ ...(Option.isSome(trustedDevice)
2897
+ ? { trustedDevice: trustedDevice.value }
2898
+ : {}),
2899
+ ...(Option.isSome(trustedDeviceCookie)
2900
+ ? { trustedDeviceCookie: trustedDeviceCookie.value }
2901
+ : {}),
2902
+ }))
2903
+ .handle("status", makeLoginApprovalStatusHandler(Option.isSome(loginApprovalReview)
2904
+ ? { loginApprovalReview: loginApprovalReview.value }
2905
+ : {}))
2906
+ .handle("finalize", makeLoginApprovalFinalizeHandler({
2907
+ authHttp,
2908
+ loginApprovalPendingCookie,
2909
+ ...(Option.isSome(loginApprovalFinalize)
2910
+ ? { loginApprovalFinalize: loginApprovalFinalize.value }
2911
+ : {}),
2912
+ ...(Option.isSome(trustedDevice)
2913
+ ? { trustedDevice: trustedDevice.value }
2914
+ : {}),
2915
+ ...(Option.isSome(trustedDeviceCookie)
2916
+ ? { trustedDeviceCookie: trustedDeviceCookie.value }
2917
+ : {}),
2918
+ }));
2919
+ }));
2920
+ export const SecurityApiLive = HttpApiBuilder.group(AuthApi, "security", Effect.fn("auth.http.security.group")(function* (handlers) {
2921
+ const loginNotification = yield* Effect.serviceOption(LoginNotification);
2922
+ return handlers.handle("reportLogin", makeLoginNotificationReportHandler(Option.isSome(loginNotification)
2923
+ ? { loginNotification: loginNotification.value }
2924
+ : {}));
2925
+ }));
2926
+ export const SecurityTimelineApiLive = HttpApiBuilder.group(SecurityTimelineHttpApi, "securityTimeline", Effect.fn("auth.http.security_timeline.group")(function* (handlers) {
2927
+ const sessions = yield* Sessions;
2928
+ const sessionCookie = yield* SessionCookie;
2929
+ const securityTimeline = yield* SecurityTimelineStore;
2930
+ return handlers.handle("list", makeSecurityTimelineListHandler({
2931
+ sessions,
2932
+ sessionCookie,
2933
+ securityTimeline,
2934
+ }));
2935
+ }));
2936
+ export const SecurityTimelineHttpApiLive = HttpApiBuilder.layer(SecurityTimelineHttpApi).pipe(Layer.provide(SecurityTimelineApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2937
+ export const OAuthProviderAuthorizationApiLive = HttpApiBuilder.group(OAuthProviderAuthorizationHttpApi, "oauthProviderAuthorization", Effect.fn("auth.http.oauth_provider_authorization.group")(function* (handlers) {
2938
+ const authorization = yield* OAuthProviderAuthorization;
2939
+ return handlers.handle("authorize", makeOAuthProviderAuthorizationHandler({ authorization }));
2940
+ }));
2941
+ export const OAuthProviderAuthorizationHttpApiLive = HttpApiBuilder.layer(OAuthProviderAuthorizationHttpApi).pipe(Layer.provide(OAuthProviderAuthorizationApiLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2942
+ export const OAuthTokenApiLive = HttpApiBuilder.group(OAuthTokenHttpApi, "oauthToken", Effect.fn("auth.http.oauth_token.group")(function* (handlers) {
2943
+ const tokenGrant = yield* OAuthAuthorizationCodeTokenGrant;
2944
+ const refreshTokenGrant = yield* Effect.serviceOption(OAuthRefreshTokenGrant);
2945
+ const clientCredentialsGrant = yield* Effect.serviceOption(OAuthClientCredentialsGrant);
2946
+ const tokenIntrospection = yield* Effect.serviceOption(OAuthTokenIntrospection);
2947
+ const tokenRevocation = yield* Effect.serviceOption(OAuthTokenRevocation);
2948
+ return handlers
2949
+ .handle("token", makeOAuthAuthorizationCodeTokenHandler({
2950
+ tokenGrant,
2951
+ ...(Option.isNone(refreshTokenGrant)
2952
+ ? {}
2953
+ : { refreshTokenGrant: refreshTokenGrant.value }),
2954
+ ...(Option.isNone(clientCredentialsGrant)
2955
+ ? {}
2956
+ : { clientCredentialsGrant: clientCredentialsGrant.value }),
2957
+ }))
2958
+ .handle("introspect", Option.isNone(tokenIntrospection)
2959
+ ? makeOAuthTokenIntrospectionNotConfiguredHandler()
2960
+ : makeOAuthTokenIntrospectionHandler({
2961
+ tokenIntrospection: tokenIntrospection.value,
2962
+ }))
2963
+ .handle("revoke", Option.isNone(tokenRevocation)
2964
+ ? makeOAuthTokenRevocationNotConfiguredHandler()
2965
+ : makeOAuthTokenRevocationHandler({
2966
+ tokenRevocation: tokenRevocation.value,
2967
+ }));
2968
+ }));
2969
+ export const OAuthTokenHttpApiLive = HttpApiBuilder.layer(OAuthTokenHttpApi).pipe(Layer.provide(OAuthTokenApiLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2970
+ export const JwtDiscoveryApiLive = HttpApiBuilder.group(JwtDiscoveryHttpApi, "jwtDiscovery", Effect.fn("auth.http.jwt_discovery.group")(function* (handlers) {
2971
+ const jwks = yield* Jwks;
2972
+ return handlers.handle("jwks", makeJwtJwksHandler({ jwks }));
2973
+ }));
2974
+ export const JwtDiscoveryHttpApiLive = HttpApiBuilder.layer(JwtDiscoveryHttpApi).pipe(Layer.provide(JwtDiscoveryApiLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2975
+ export const OidcDiscoveryApiLive = HttpApiBuilder.group(OidcDiscoveryHttpApi, "oidcDiscovery", Effect.fn("auth.http.oidc_discovery.group")(function* (handlers) {
2976
+ const metadata = yield* OidcDiscoveryMetadata;
2977
+ return handlers.handle("openidConfiguration", makeOidcDiscoveryMetadataHandler({ metadata }));
2978
+ }));
2979
+ export const OidcDiscoveryHttpApiLive = HttpApiBuilder.layer(OidcDiscoveryHttpApi).pipe(Layer.provide(OidcDiscoveryApiLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2980
+ export const AdminSecurityTimelineApiLive = HttpApiBuilder.group(AdminSecurityTimelineHttpApi, "adminSecurityTimeline", Effect.fn("auth.http.admin_security_timeline.group")(function* (handlers) {
2981
+ const sessions = yield* Sessions;
2982
+ const sessionCookie = yield* SessionCookie;
2983
+ const securityTimeline = yield* SecurityTimelineStore;
2984
+ const authorization = yield* AdminSecurityTimelineAuthorization;
2985
+ return handlers.handle("list", makeAdminSecurityTimelineListHandler({
2986
+ sessions,
2987
+ sessionCookie,
2988
+ securityTimeline,
2989
+ authorization,
2990
+ }));
2991
+ }));
2992
+ export const AdminSecurityTimelineHttpApiLive = HttpApiBuilder.layer(AdminSecurityTimelineHttpApi).pipe(Layer.provide(AdminSecurityTimelineApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
2993
+ export const TrustedDeviceApiLive = HttpApiBuilder.group(TrustedDeviceHttpApi, "trustedDevice", Effect.fn("auth.http.trusted_device.group")(function* (handlers) {
2994
+ const sessions = yield* Sessions;
2995
+ const sessionCookie = yield* SessionCookie;
2996
+ const trustedDevices = yield* TrustedDeviceStore;
2997
+ return handlers
2998
+ .handle("list", makeTrustedDeviceListHandler({ sessions, sessionCookie, trustedDevices }))
2999
+ .handle("revoke", makeTrustedDeviceRevokeHandler({ sessions, sessionCookie, trustedDevices }));
3000
+ }));
3001
+ export const TrustedDeviceHttpApiLive = HttpApiBuilder.layer(TrustedDeviceHttpApi).pipe(Layer.provide(TrustedDeviceApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
3002
+ export const AdminTrustedDeviceApiLive = HttpApiBuilder.group(AdminTrustedDeviceHttpApi, "adminTrustedDevice", Effect.fn("auth.http.admin_trusted_device.group")(function* (handlers) {
3003
+ const sessions = yield* Sessions;
3004
+ const sessionCookie = yield* SessionCookie;
3005
+ const trustedDevices = yield* TrustedDeviceStore;
3006
+ const authorization = yield* AdminTrustedDeviceAuthorization;
3007
+ return handlers
3008
+ .handle("list", makeAdminTrustedDeviceListHandler({
3009
+ sessions,
3010
+ sessionCookie,
3011
+ trustedDevices,
3012
+ authorization,
3013
+ }))
3014
+ .handle("revoke", makeAdminTrustedDeviceRevokeHandler({
3015
+ sessions,
3016
+ sessionCookie,
3017
+ trustedDevices,
3018
+ authorization,
3019
+ }));
3020
+ }));
3021
+ export const AdminTrustedDeviceHttpApiLive = HttpApiBuilder.layer(AdminTrustedDeviceHttpApi).pipe(Layer.provide(AdminTrustedDeviceApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
3022
+ const AuthHttpApiBaseLive = HttpApiBuilder.layer(AuthApi).pipe(Layer.provide(PasswordApiLive), Layer.provide(SessionApiLive), Layer.provide(EmailVerificationApiLive), Layer.provide(EmailOtpApiLive), Layer.provide(MagicLinkApiLive), Layer.provide(LoginApprovalApiLive), Layer.provide(SecurityApiLive), Layer.provide(AuthOriginCheckMiddlewareConfigLive), Layer.provide(AuthSchemaErrorMiddlewareLive));
3023
+ export const AuthHttpApiBareLive = AuthHttpApiBaseLive.pipe(Layer.provide(AuthApiRateLimitNoopLive));
3024
+ export const AuthHttpApiLive = AuthHttpApiBaseLive.pipe(Layer.provide(AuthApiRateLimitLive));
3025
+ export { AuthResult };
3026
+ //# sourceMappingURL=Api.js.map