Skip to content

Commit 1984aed

Browse files
committed
fix(Auth): improve redirect logic
1 parent f248bb2 commit 1984aed

File tree

1 file changed

+29
-34
lines changed

1 file changed

+29
-34
lines changed

server/api/auth.ts

+29-34
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const SALT_ROUNDS = 10;
2020
const JWT_SECRET = new TextEncoder().encode(process.env.SECRETKEY);
2121
const JWT_COOKIE_DOMAIN = (process.env.PRODUCTIONURLS || "").split(",")[0];
2222
const SESSION_DEFAULT_EXPIRY_MINUTES = 60 * 24 * 7; // 7 days
23-
const SESSION_DEFAULT_EXPIRY_MILLISECONDS = SESSION_DEFAULT_EXPIRY_MINUTES * 60 * 1000;
23+
const SESSION_DEFAULT_EXPIRY_MILLISECONDS =
24+
SESSION_DEFAULT_EXPIRY_MINUTES * 60 * 1000;
2425

2526
const oidcBase = `https://${process.env.OIDC_HOST}`;
2627
const oidcAuth = `${oidcBase}/cas/oidc/authorize`;
@@ -75,17 +76,23 @@ function splitSessionJWT(sessionJWT: string) {
7576
* @param {string} uuid - The User UUID to initialize the session for.
7677
* @param {string} ticket - A CAS ticket ID to use for the session.
7778
*/
78-
async function createAndAttachLocalSession(res: Response, uuid: string, ticket?: string) {
79+
async function createAndAttachLocalSession(
80+
res: Response,
81+
uuid: string,
82+
ticket?: string
83+
) {
7984
const sessionId = uuidv4();
8085
const sessionCreated = new Date();
81-
const sessionExpiry = new Date(sessionCreated.getTime() + SESSION_DEFAULT_EXPIRY_MILLISECONDS);
86+
const sessionExpiry = new Date(
87+
sessionCreated.getTime() + SESSION_DEFAULT_EXPIRY_MILLISECONDS
88+
);
8289
const session = new Session({
8390
sessionId,
8491
userId: uuid,
8592
valid: true,
8693
createdAt: sessionCreated,
8794
expiresAt: sessionExpiry,
88-
...ticket && { sessionTicket: ticket },
95+
...(ticket && { sessionTicket: ticket }),
8996
});
9097

9198
await session.save();
@@ -153,17 +160,6 @@ async function initLogin(req: Request, res: Response) {
153160
secure: true,
154161
};
155162

156-
if (
157-
process.env.CONDUCTOR_DOMAIN &&
158-
process.env.CONDUCTOR_DOMAIN !== "commons.libretexts.org"
159-
) {
160-
const authRedirectURL = `${oidcCallbackProto}://${process.env.CONDUCTOR_DOMAIN}`;
161-
res.cookie("conductor_auth_redirect", authRedirectURL, {
162-
encode: String,
163-
httpOnly: true,
164-
...(process.env.NODE_ENV === "production" && prodCookieConfig),
165-
});
166-
}
167163
res.cookie("oidc_state", base64State, {
168164
encode: String,
169165
httpOnly: true,
@@ -235,7 +231,7 @@ async function completeLogin(req: Request, res: Response) {
235231
}
236232

237233
// Session ID (sid) from id_token will be used as the ticket identifier
238-
const idDecoded = decodeJwt(id_token)
234+
const idDecoded = decodeJwt(id_token);
239235
const ticketID = idDecoded?.sid?.toString();
240236

241237
// Verify ID token with CAS public key set
@@ -348,29 +344,28 @@ async function completeLogin(req: Request, res: Response) {
348344
// Create local session
349345
await createAndAttachLocalSession(res, authUser.uuid, ticketID);
350346

351-
// Redirect user
352-
let redirectURL = req.hostname;
353-
if (req.cookies.conductor_auth_redirect) {
354-
redirectURL = req.cookies.conductor_auth_redirect;
355-
} else {
356-
const domain =
357-
process.env.NODE_ENV === "production"
358-
? process.env.CONDUCTOR_DOMAIN
359-
: `localhost:${process.env.CLIENT_PORT || 3000}`;
360-
redirectURL = `${oidcCallbackProto}://${domain}`;
361-
}
347+
// Determine redirect URL
348+
let finalRedirectURL = `${req.protocol}://${req.get("host")}`;
349+
350+
// Check if redirectURI is a full URL
362351
if (state.redirectURI && isFullURL(state.redirectURI)) {
363-
redirectURL = state.redirectURI;
364-
} else {
352+
finalRedirectURL = state.redirectURI;
353+
} else if (state.redirectURI && !isFullURL(state.redirectURI)) {
365354
// redirectURI is only a path or not provided
366-
redirectURL = assembleUrl([redirectURL, state.redirectURI ?? "home"]);
355+
finalRedirectURL = assembleUrl([finalRedirectURL, state.redirectURI]);
356+
} else {
357+
// Default to home if no redirectURI is provided
358+
finalRedirectURL = assembleUrl([finalRedirectURL, "home"]);
367359
}
368360

369361
if (!state.redirectURI && isNewMember) {
370-
redirectURL = `${redirectURL}?newmember=true`;
362+
const _final = new URL(finalRedirectURL);
363+
const _params = new URLSearchParams(_final.search);
364+
_params.set("newmember", "true");
365+
finalRedirectURL = `${_final.origin}${_final.pathname}?${_params.toString()}`;
371366
}
372367

373-
return res.redirect(redirectURL);
368+
return res.redirect(finalRedirectURL);
374369
} catch (e) {
375370
debugError(e);
376371
return res.status(500).send({
@@ -727,8 +722,8 @@ async function verifyRequest(req: Request, res: Response, next: NextFunction) {
727722
} catch (e: any) {
728723
let tokenExpired = false;
729724
let sessionInvalid = false;
730-
console.log('VERIFY REQUEST ERROR')
731-
console.log(e)
725+
console.log("VERIFY REQUEST ERROR");
726+
console.log(e);
732727
if (e.code === "ERR_JWT_EXPIRED") {
733728
tokenExpired = true;
734729
} else if (e.message === "ERR_BAD_SESSION") {

0 commit comments

Comments
 (0)