1import * as cip from "@distilled.cloud/aws/cognito-identity-provider";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import * as Binding from "../../Binding.ts";
5import { isBindingHost } from "../Lambda/Function.ts";
6import { cognitoMethods } from "./BindingHttp.ts";
7import { UserPoolAuth, type UserPoolAuthClient } from "./UserPoolAuth.ts";
8import type { UserPoolClient } from "./UserPoolClient.ts";
9
10/** The injected identifier field, in the distilled wire type (Cognito marks
11 * `ClientId` sensitive, so the field accepts `string | Redacted<string>`). */
12type ClientIdField = Pick<cip.SignUpRequest, "ClientId">;
13
14/**
15 * HTTP implementation of {@link UserPoolAuth}. The token-based auth-flow
16 * operations are unauthenticated (Cognito does not evaluate IAM for them),
17 * so the deploy-time half only records the binding — no policy statements
18 * are attached.
19 */
20export const UserPoolAuthHttp = Layer.effect(
21 UserPoolAuth,
22 Effect.gen(function* () {
23 const signUp = yield* cip.signUp;
24 const confirmSignUp = yield* cip.confirmSignUp;
25 const resendConfirmationCode = yield* cip.resendConfirmationCode;
26 const initiateAuth = yield* cip.initiateAuth;
27 const respondToAuthChallenge = yield* cip.respondToAuthChallenge;
28 const forgotPassword = yield* cip.forgotPassword;
29 const confirmForgotPassword = yield* cip.confirmForgotPassword;
30 const getUser = yield* cip.getUser;
31 const globalSignOut = yield* cip.globalSignOut;
32 const revokeToken = yield* cip.revokeToken;
33 const getTokensFromRefreshToken = yield* cip.getTokensFromRefreshToken;
34 const changePassword = yield* cip.changePassword;
35 const updateUserAttributes = yield* cip.updateUserAttributes;
36 const deleteUserAttributes = yield* cip.deleteUserAttributes;
37 const getUserAttributeVerificationCode =
38 yield* cip.getUserAttributeVerificationCode;
39 const verifyUserAttribute = yield* cip.verifyUserAttribute;
40 const setUserMFAPreference = yield* cip.setUserMFAPreference;
41 const associateSoftwareToken = yield* cip.associateSoftwareToken;
42 const verifySoftwareToken = yield* cip.verifySoftwareToken;
43 const getUserAuthFactors = yield* cip.getUserAuthFactors;
44 const deleteUser = yield* cip.deleteUser;
45
46 return Effect.fn(function* <C extends UserPoolClient>(client: C) {
47 const ClientId = yield* client.clientId;
48 if (!globalThis.__ALCHEMY_RUNTIME__) {
49 const host = yield* Binding.Host;
50 if (isBindingHost(host)) {
51 // No IAM is required for the public auth flows; the binding is
52 // recorded so the app client deploys before the function.
53 yield* host.bind`Allow(${host}, AWS.Cognito.UserPoolAuth(${client}))`(
54 { policyStatements: [] },
55 );
56 }
57 }
58 const methods = cognitoMethods(
59 "AWS.Cognito.UserPoolAuth",
60 client.LogicalId,
61 );
62 const withClient = methods.injecting(
63 Effect.map(ClientId, (id): ClientIdField => ({ ClientId: id })),
64 );
65 const authClient: UserPoolAuthClient = {
66 // client-scoped flows — the app client ID is injected
67 signUp: withClient("signUp", signUp),
68 confirmSignUp: withClient("confirmSignUp", confirmSignUp),
69 resendConfirmationCode: withClient(
70 "resendConfirmationCode",
71 resendConfirmationCode,
72 ),
73 initiateAuth: withClient("initiateAuth", initiateAuth),
74 respondToAuthChallenge: withClient(
75 "respondToAuthChallenge",
76 respondToAuthChallenge,
77 ),
78 forgotPassword: withClient("forgotPassword", forgotPassword),
79 confirmForgotPassword: withClient(
80 "confirmForgotPassword",
81 confirmForgotPassword,
82 ),
83 revokeToken: withClient("revokeToken", revokeToken),
84 getTokensFromRefreshToken: withClient(
85 "getTokensFromRefreshToken",
86 getTokensFromRefreshToken,
87 ),
88 // token-scoped self-service — authorized by the access token itself
89 getUser: methods.plain("getUser", getUser),
90 globalSignOut: methods.plain("globalSignOut", globalSignOut),
91 changePassword: methods.plain("changePassword", changePassword),
92 updateUserAttributes: methods.plain(
93 "updateUserAttributes",
94 updateUserAttributes,
95 ),
96 deleteUserAttributes: methods.plain(
97 "deleteUserAttributes",
98 deleteUserAttributes,
99 ),
100 getUserAttributeVerificationCode: methods.plain(
101 "getUserAttributeVerificationCode",
102 getUserAttributeVerificationCode,
103 ),
104 verifyUserAttribute: methods.plain(
105 "verifyUserAttribute",
106 verifyUserAttribute,
107 ),
108 setUserMFAPreference: methods.plain(
109 "setUserMFAPreference",
110 setUserMFAPreference,
111 ),
112 associateSoftwareToken: methods.plain(
113 "associateSoftwareToken",
114 associateSoftwareToken,
115 ),
116 verifySoftwareToken: methods.plain(
117 "verifySoftwareToken",
118 verifySoftwareToken,
119 ),
120 getUserAuthFactors: methods.plain(
121 "getUserAuthFactors",
122 getUserAuthFactors,
123 ),
124 deleteUser: methods.plain("deleteUser", deleteUser),
125 };
126 return authClient;
127 });
128 }),
129);