-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauthRouter.ts
More file actions
180 lines (159 loc) · 5.88 KB
/
Copy pathauthRouter.ts
File metadata and controls
180 lines (159 loc) · 5.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import * as Sentry from "@sentry/node";
import { Router } from "express";
import { GraphQLError } from "graphql";
import { LoginTypes, handleUserLogin } from "@/core/user/handleUserLogin/handleUserLogin";
import { MePrismaType } from "@/core/user/userPrismaTypes";
import { CustomErrorCodes } from "@/graphql/errors";
import { telegramValidator } from "@/telegram/validator";
import { redirectAtLogin } from "../stytch/redirectAtLogin";
import { sessionDurationMinutes, stytchClient } from "../stytch/stytchClient";
const authRouter = Router();
// handles login / signup for all auth flows that user a access token (oauth / magiclink)
// creates session, user, and identities for user
authRouter.get("/token", async (req, res, next) => {
let tokenType: string | undefined = undefined;
try {
const { stytch_token_type, token } = req.query;
tokenType = stytch_token_type as string;
// for when this endpoint is called to attach identity to existing user
// eslint-disable-next-line
const exitingSessionToken: string | undefined = req.cookies["stytch_session"] as string;
let sessionToken: string | undefined;
if (typeof token !== "string" || !token || !stytch_token_type)
throw Error("Missing authentication token");
if (stytch_token_type === "oauth") {
const stytchOAuthentication = await stytchClient.oauth.authenticate({
token: token,
session_duration_minutes: sessionDurationMinutes,
});
sessionToken = stytchOAuthentication.session_token;
await handleUserLogin({ res, type: LoginTypes.Oauth, stytchOAuthentication });
} else if (stytch_token_type === "magic_links" || stytch_token_type === "login") {
const stytchMagicAuthentication = await stytchClient.magicLinks.authenticate({
token,
session_duration_minutes: sessionDurationMinutes,
// if user is already logged in, use their session token
session_token: exitingSessionToken,
});
sessionToken = stytchMagicAuthentication.session_token;
await handleUserLogin({
res,
type: LoginTypes.MagicLink,
stytchMagicLinkAuthentication: stytchMagicAuthentication,
});
}
if (sessionToken) res.cookie("stytch_session", sessionToken);
redirectAtLogin({ req, res });
} catch (error) {
Sentry.captureException(error, {
tags: { location: "auth" },
contexts: {
auth: { type: "login", method: tokenType },
},
});
next(error);
}
});
// Attaches Discord login to an existing Stytch account
// sends user oauth token which they use to begin the oauth flow
// at which point user is directed through normal /token flow
authRouter.post("/attach-discord", async (req, res, next) => {
try {
//eslint-disable-next-line
const session_token = req.cookies["stytch_session"] as string;
if (!session_token) res.status(401).send();
const resp = await stytchClient.oauth.attach({
session_token,
provider: "discord",
});
res.send(resp.oauth_attach_token);
} catch (error) {
Sentry.captureException(error, {
tags: { location: "auth" },
contexts: {
auth: { type: "attach", method: "discord" },
},
});
next(error);
}
});
// creates blockchain identities for user on authentication
// session already created for user on FE --> user also already created via authenticateSession
authRouter.post("/crypto", async (req, res, next) => {
try {
//eslint-disable-next-line
const session_token = req.cookies["stytch_session"] as string;
if (!session_token) res.status(401).send();
const session = await stytchClient.sessions.authenticate({
session_token,
session_duration_minutes: sessionDurationMinutes,
});
await handleUserLogin({
res: res,
type: LoginTypes.Blockchain,
stytchSession: session,
});
redirectAtLogin({ req, res });
// res.status(200).send();
} catch (error) {
Sentry.captureException(error, {
tags: { location: "auth" },
contexts: {
auth: { type: "login", method: "crypto" },
},
});
next(error);
}
});
// creates email identities for user on authentication
// session already created for user on FE --> user also already created via authenticateSession
authRouter.post("/password", async (req, res, next) => {
try {
//eslint-disable-next-line
const session_token = req.cookies["stytch_session"] as string;
const stytchSession = await stytchClient.sessions.authenticate({
session_token,
session_duration_minutes: sessionDurationMinutes,
});
// const sessionToken = sessionData.session_token;
if (!session_token) {
res.status(401).send();
}
await handleUserLogin({ res, type: LoginTypes.Password, stytchSession: stytchSession });
redirectAtLogin({ req, res });
} catch (error) {
Sentry.captureException(error, {
tags: { location: "auth" },
contexts: {
auth: { type: "login", method: "password" },
},
});
next(error);
}
});
authRouter.post("/telegram", async (req, res, next) => {
try {
//eslint-disable-next-line
const data = new Map(Object.entries(req.body));
// note telegramValidator is implicitly using botToken to validate
// if FE Telegram bot token is different from BE bot token, this will fail
// @ts-expect-error TODO
const telegramUserData = await telegramValidator.validate(data);
const user = res.locals.user as MePrismaType | undefined;
if (!user)
throw new GraphQLError("Unauthenticated", {
extensions: { code: CustomErrorCodes.Unauthenticated },
});
await handleUserLogin({ res, type: LoginTypes.Telegram, user, telegramUserData });
} catch (error) {
Sentry.captureException(error, {
tags: { location: "auth" },
contexts: {
auth: { type: "attach", method: "telegram" },
},
});
res.sendStatus(500);
next(error);
}
});
export default authRouter;