mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-19 02:10:33 -05:00
154 lines
4.3 KiB
TypeScript
154 lines
4.3 KiB
TypeScript
import * as Sentry from "@sentry/nextjs";
|
|
import NextAuth, { Account, Profile, User } from "next-auth";
|
|
import { AdapterUser } from "next-auth/adapters";
|
|
import { CredentialInput } from "next-auth/providers/credentials";
|
|
import { logger } from "@formbricks/logger";
|
|
import { IS_PRODUCTION, SENTRY_DSN } from "@/lib/constants";
|
|
import { authOptions as baseAuthOptions } from "@/modules/auth/lib/authOptions";
|
|
import { queueAuditEventBackground } from "@/modules/ee/audit-logs/lib/handler";
|
|
import { UNKNOWN_DATA } from "@/modules/ee/audit-logs/types/audit-log";
|
|
|
|
export const fetchCache = "force-no-store";
|
|
|
|
const getAuthMethod = (account: Account | null) => {
|
|
if (account?.provider === "credentials") {
|
|
return "password";
|
|
}
|
|
|
|
if (account?.provider === "token") {
|
|
return "email_verification";
|
|
}
|
|
|
|
if (account?.provider) {
|
|
return "sso";
|
|
}
|
|
|
|
return "unknown";
|
|
};
|
|
|
|
const handler = async (req: Request, ctx: any) => {
|
|
const eventId = req.headers.get("x-request-id") ?? undefined;
|
|
|
|
const authOptions = {
|
|
...baseAuthOptions,
|
|
callbacks: {
|
|
...baseAuthOptions.callbacks,
|
|
async session(params: any) {
|
|
let result: any = params.session;
|
|
let error: any = undefined;
|
|
|
|
try {
|
|
if (baseAuthOptions.callbacks?.session) {
|
|
result = await baseAuthOptions.callbacks.session(params);
|
|
}
|
|
} catch (err) {
|
|
error = err;
|
|
logger.withContext({ eventId, err }).error("Session callback failed");
|
|
|
|
if (SENTRY_DSN && IS_PRODUCTION) {
|
|
Sentry.captureException(err);
|
|
}
|
|
}
|
|
|
|
if (error) throw error;
|
|
return result;
|
|
},
|
|
async signIn({
|
|
user,
|
|
account,
|
|
profile,
|
|
email,
|
|
credentials,
|
|
}: {
|
|
user: User | AdapterUser;
|
|
account: Account | null;
|
|
profile?: Profile;
|
|
email?: { verificationRequest?: boolean };
|
|
credentials?: Record<string, CredentialInput>;
|
|
}) {
|
|
let result: boolean | string = true;
|
|
let error: any = undefined;
|
|
const authMethod = getAuthMethod(account);
|
|
|
|
try {
|
|
if (baseAuthOptions.callbacks?.signIn) {
|
|
result = await baseAuthOptions.callbacks.signIn({
|
|
user,
|
|
account,
|
|
profile,
|
|
email,
|
|
credentials,
|
|
});
|
|
}
|
|
} catch (err) {
|
|
error = err;
|
|
result = false;
|
|
|
|
logger.withContext({ eventId, err }).error("User sign-in failed");
|
|
|
|
if (SENTRY_DSN && IS_PRODUCTION) {
|
|
Sentry.captureException(err);
|
|
}
|
|
}
|
|
|
|
if (result === false) {
|
|
queueAuditEventBackground({
|
|
action: "signedIn",
|
|
targetType: "user",
|
|
userId: user?.id ?? UNKNOWN_DATA,
|
|
targetId: user?.id ?? UNKNOWN_DATA,
|
|
organizationId: UNKNOWN_DATA,
|
|
status: "failure",
|
|
userType: "user",
|
|
newObject: {
|
|
...user,
|
|
authMethod,
|
|
provider: account?.provider,
|
|
...(error instanceof Error ? { errorMessage: error.message } : {}),
|
|
},
|
|
eventId,
|
|
});
|
|
}
|
|
|
|
if (error) throw error;
|
|
return result;
|
|
},
|
|
},
|
|
events: {
|
|
...baseAuthOptions.events,
|
|
async signIn({ user, account, isNewUser }: any) {
|
|
try {
|
|
await baseAuthOptions.events?.signIn?.({ user, account, isNewUser });
|
|
} catch (err) {
|
|
logger.withContext({ eventId, err }).error("Sign-in event callback failed");
|
|
|
|
if (SENTRY_DSN && IS_PRODUCTION) {
|
|
Sentry.captureException(err);
|
|
}
|
|
}
|
|
|
|
queueAuditEventBackground({
|
|
action: "signedIn",
|
|
targetType: "user",
|
|
userId: user?.id ?? UNKNOWN_DATA,
|
|
targetId: user?.id ?? UNKNOWN_DATA,
|
|
organizationId: UNKNOWN_DATA,
|
|
status: "success",
|
|
userType: "user",
|
|
newObject: {
|
|
...user,
|
|
authMethod: getAuthMethod(account),
|
|
provider: account?.provider,
|
|
sessionStrategy: "database",
|
|
isNewUser: isNewUser ?? false,
|
|
},
|
|
});
|
|
},
|
|
},
|
|
};
|
|
|
|
return NextAuth(authOptions)(req, ctx);
|
|
};
|
|
|
|
export { handler as GET, handler as POST };
|