Преглед изворни кода

set resource session cookie in proxy via param

Milo Schwartz пре 7 месеци
родитељ
комит
d7c4bc43a4

+ 7 - 2
config.example.yml

@@ -2,6 +2,7 @@ app:
     base_url: http://localhost:3000
     base_url: http://localhost:3000
     log_level: warning
     log_level: warning
     save_logs: false
     save_logs: false
+    sessionCookieName: session
 
 
 server:
 server:
     external_port: 3000
     external_port: 3000
@@ -14,12 +15,16 @@ traefik:
     http_entrypoint: web
     http_entrypoint: web
     https_entrypoint: websecure
     https_entrypoint: websecure
 
 
+badger:
+    session_query_parameter: __pang_sess
+    resource_session_cookie_name: resource_session
+
 gerbil:
 gerbil:
     start_port: 51820
     start_port: 51820
     base_endpoint: localhost
     base_endpoint: localhost
     block_size: 16
     block_size: 16
-    subnet_group: 10.0.0.0/8 
+    subnet_group: 10.0.0.0/8
 
 
 rate_limit:
 rate_limit:
     window_minutes: 1
     window_minutes: 1
-    max_requests: 100
+    max_requests: 100

+ 2 - 2
server/auth/index.ts

@@ -13,7 +13,7 @@ import config from "@server/config";
 import type { RandomReader } from "@oslojs/crypto/random";
 import type { RandomReader } from "@oslojs/crypto/random";
 import { generateRandomString } from "@oslojs/crypto/random";
 import { generateRandomString } from "@oslojs/crypto/random";
 
 
-export const SESSION_COOKIE_NAME = "session";
+export const SESSION_COOKIE_NAME = config.server.session_cookie_name;
 export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
 export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
 export const SECURE_COOKIES = config.server.secure_cookies;
 export const SECURE_COOKIES = config.server.secure_cookies;
 export const COOKIE_DOMAIN =
 export const COOKIE_DOMAIN =
@@ -63,7 +63,7 @@ export async function validateSessionToken(
             .where(eq(sessions.sessionId, session.sessionId));
             .where(eq(sessions.sessionId, session.sessionId));
         return { session: null, user: null };
         return { session: null, user: null };
     }
     }
-    if (Date.now() >= session.expiresAt - (SESSION_COOKIE_EXPIRES / 2)) {
+    if (Date.now() >= session.expiresAt - SESSION_COOKIE_EXPIRES / 2) {
         session.expiresAt = new Date(
         session.expiresAt = new Date(
             Date.now() + SESSION_COOKIE_EXPIRES,
             Date.now() + SESSION_COOKIE_EXPIRES,
         ).getTime();
         ).getTime();

+ 17 - 17
server/auth/resource.ts

@@ -15,12 +15,12 @@ export async function createResourceSession(opts: {
 }): Promise<ResourceSession> {
 }): Promise<ResourceSession> {
     if (!opts.passwordId && !opts.pincodeId) {
     if (!opts.passwordId && !opts.pincodeId) {
         throw new Error(
         throw new Error(
-            "At least one of passwordId or pincodeId must be provided"
+            "At least one of passwordId or pincodeId must be provided",
         );
         );
     }
     }
 
 
     const sessionId = encodeHexLowerCase(
     const sessionId = encodeHexLowerCase(
-        sha256(new TextEncoder().encode(opts.token))
+        sha256(new TextEncoder().encode(opts.token)),
     );
     );
 
 
     const session: ResourceSession = {
     const session: ResourceSession = {
@@ -38,10 +38,10 @@ export async function createResourceSession(opts: {
 
 
 export async function validateResourceSessionToken(
 export async function validateResourceSessionToken(
     token: string,
     token: string,
-    resourceId: number
+    resourceId: number,
 ): Promise<ResourceSessionValidationResult> {
 ): Promise<ResourceSessionValidationResult> {
     const sessionId = encodeHexLowerCase(
     const sessionId = encodeHexLowerCase(
-        sha256(new TextEncoder().encode(token))
+        sha256(new TextEncoder().encode(token)),
     );
     );
     const result = await db
     const result = await db
         .select()
         .select()
@@ -49,8 +49,8 @@ export async function validateResourceSessionToken(
         .where(
         .where(
             and(
             and(
                 eq(resourceSessions.sessionId, sessionId),
                 eq(resourceSessions.sessionId, sessionId),
-                eq(resourceSessions.resourceId, resourceId)
-            )
+                eq(resourceSessions.resourceId, resourceId),
+            ),
         );
         );
 
 
     if (result.length < 1) {
     if (result.length < 1) {
@@ -61,7 +61,7 @@ export async function validateResourceSessionToken(
 
 
     if (Date.now() >= resourceSession.expiresAt - SESSION_COOKIE_EXPIRES / 2) {
     if (Date.now() >= resourceSession.expiresAt - SESSION_COOKIE_EXPIRES / 2) {
         resourceSession.expiresAt = new Date(
         resourceSession.expiresAt = new Date(
-            Date.now() + SESSION_COOKIE_EXPIRES
+            Date.now() + SESSION_COOKIE_EXPIRES,
         ).getTime();
         ).getTime();
         await db
         await db
             .update(resourceSessions)
             .update(resourceSessions)
@@ -75,7 +75,7 @@ export async function validateResourceSessionToken(
 }
 }
 
 
 export async function invalidateResourceSession(
 export async function invalidateResourceSession(
-    sessionId: string
+    sessionId: string,
 ): Promise<void> {
 ): Promise<void> {
     await db
     await db
         .delete(resourceSessions)
         .delete(resourceSessions)
@@ -87,7 +87,7 @@ export async function invalidateAllSessions(
     method?: {
     method?: {
         passwordId?: number;
         passwordId?: number;
         pincodeId?: number;
         pincodeId?: number;
-    }
+    },
 ): Promise<void> {
 ): Promise<void> {
     if (method?.passwordId) {
     if (method?.passwordId) {
         await db
         await db
@@ -95,8 +95,8 @@ export async function invalidateAllSessions(
             .where(
             .where(
                 and(
                 and(
                     eq(resourceSessions.resourceId, resourceId),
                     eq(resourceSessions.resourceId, resourceId),
-                    eq(resourceSessions.passwordId, method.passwordId)
-                )
+                    eq(resourceSessions.passwordId, method.passwordId),
+                ),
             );
             );
     } else if (method?.pincodeId) {
     } else if (method?.pincodeId) {
         await db
         await db
@@ -104,8 +104,8 @@ export async function invalidateAllSessions(
             .where(
             .where(
                 and(
                 and(
                     eq(resourceSessions.resourceId, resourceId),
                     eq(resourceSessions.resourceId, resourceId),
-                    eq(resourceSessions.pincodeId, method.pincodeId)
-                )
+                    eq(resourceSessions.pincodeId, method.pincodeId),
+                ),
             );
             );
     } else {
     } else {
         await db
         await db
@@ -117,18 +117,18 @@ export async function invalidateAllSessions(
 export function serializeResourceSessionCookie(
 export function serializeResourceSessionCookie(
     token: string,
     token: string,
     fqdn: string,
     fqdn: string,
-    secure: boolean
+    secure: boolean,
 ): string {
 ): string {
     if (secure) {
     if (secure) {
-        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Secure; Domain=${fqdn}`;
+        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Secure; Domain=.localhost`;
     } else {
     } else {
-        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Domain=${fqdn}`;
+        return `${SESSION_COOKIE_NAME}=${token}; HttpOnly; SameSite=Lax; Max-Age=${SESSION_COOKIE_EXPIRES}; Path=/; Domain=.localhost`;
     }
     }
 }
 }
 
 
 export function createBlankResourceSessionTokenCookie(
 export function createBlankResourceSessionTokenCookie(
     fqdn: string,
     fqdn: string,
-    secure: boolean
+    secure: boolean,
 ): string {
 ): string {
     if (secure) {
     if (secure) {
         return `${SESSION_COOKIE_NAME}=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/; Secure; Domain=${fqdn}`;
         return `${SESSION_COOKIE_NAME}=; HttpOnly; SameSite=Lax; Max-Age=0; Path=/; Secure; Domain=${fqdn}`;

+ 12 - 4
server/config.ts

@@ -24,6 +24,11 @@ const environmentSchema = z.object({
         internal_hostname: z.string(),
         internal_hostname: z.string(),
         secure_cookies: z.boolean(),
         secure_cookies: z.boolean(),
         signup_secret: z.string().optional(),
         signup_secret: z.string().optional(),
+        session_cookie_name: z.string(),
+    }),
+    badger: z.object({
+        session_query_parameter: z.string(),
+        resource_session_cookie_name: z.string(),
     }),
     }),
     traefik: z.object({
     traefik: z.object({
         http_entrypoint: z.string(),
         http_entrypoint: z.string(),
@@ -68,7 +73,7 @@ const loadConfig = (configPath: string) => {
     } catch (error) {
     } catch (error) {
         if (error instanceof Error) {
         if (error instanceof Error) {
             throw new Error(
             throw new Error(
-                `Error loading configuration file: ${error.message}`
+                `Error loading configuration file: ${error.message}`,
             );
             );
         }
         }
         throw error;
         throw error;
@@ -90,21 +95,21 @@ if (!environment) {
         try {
         try {
             const exampleConfigContent = fs.readFileSync(
             const exampleConfigContent = fs.readFileSync(
                 exampleConfigPath,
                 exampleConfigPath,
-                "utf8"
+                "utf8",
             );
             );
             fs.writeFileSync(configFilePath1, exampleConfigContent, "utf8");
             fs.writeFileSync(configFilePath1, exampleConfigContent, "utf8");
             environment = loadConfig(configFilePath1);
             environment = loadConfig(configFilePath1);
         } catch (error) {
         } catch (error) {
             if (error instanceof Error) {
             if (error instanceof Error) {
                 throw new Error(
                 throw new Error(
-                    `Error creating configuration file from example: ${error.message}`
+                    `Error creating configuration file from example: ${error.message}`,
                 );
                 );
             }
             }
             throw error;
             throw error;
         }
         }
     } else {
     } else {
         throw new Error(
         throw new Error(
-            "No configuration file found and no example configuration available"
+            "No configuration file found and no example configuration available",
         );
         );
     }
     }
 }
 }
@@ -126,5 +131,8 @@ process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED = parsedConfig.data.flags
     ?.require_email_verification
     ?.require_email_verification
     ? "true"
     ? "true"
     : "false";
     : "false";
+process.env.SESSION_COOKIE_NAME = parsedConfig.data.server.session_cookie_name;
+process.env.RESOURCE_SESSION_QUERY_PARAM_NAME =
+    parsedConfig.data.badger.session_query_parameter;
 
 
 export default parsedConfig.data;
 export default parsedConfig.data;

+ 3 - 0
server/routers/auth/login.ts

@@ -16,6 +16,7 @@ import { z } from "zod";
 import { fromError } from "zod-validation-error";
 import { fromError } from "zod-validation-error";
 import { verifyTotpCode } from "@server/auth/2fa";
 import { verifyTotpCode } from "@server/auth/2fa";
 import config from "@server/config";
 import config from "@server/config";
+import logger from "@server/logger";
 
 
 export const loginBodySchema = z.object({
 export const loginBodySchema = z.object({
     email: z.string().email(),
     email: z.string().email(),
@@ -125,6 +126,8 @@ export async function login(
         await createSession(token, existingUser.userId);
         await createSession(token, existingUser.userId);
         const cookie = serializeSessionCookie(token);
         const cookie = serializeSessionCookie(token);
 
 
+        logger.debug(cookie);
+
         res.appendHeader("Set-Cookie", cookie);
         res.appendHeader("Set-Cookie", cookie);
 
 
         if (
         if (

+ 1 - 1
server/routers/badger/verifySession.ts

@@ -93,7 +93,7 @@ export async function verifyResourceSession(
             return allowed(res);
             return allowed(res);
         }
         }
 
 
-        const redirectUrl = `${config.app.base_url}/${resource.orgId}/auth/resource/${resource.resourceId}?r=${originalRequestURL}`;
+        const redirectUrl = `${config.app.base_url}/auth/resource/${resource.resourceId}?redirect=${originalRequestURL}`;
 
 
         if (sso && sessions.session) {
         if (sso && sessions.session) {
             const { session, user } = await validateSessionToken(
             const { session, user } = await validateSessionToken(

+ 32 - 26
server/routers/resource/authWithPassword.ts

@@ -27,12 +27,13 @@ export const authWithPasswordParamsSchema = z.object({
 
 
 export type AuthWithPasswordResponse = {
 export type AuthWithPasswordResponse = {
     codeRequested?: boolean;
     codeRequested?: boolean;
+    session?: string;
 };
 };
 
 
 export async function authWithPassword(
 export async function authWithPassword(
     req: Request,
     req: Request,
     res: Response,
     res: Response,
-    next: NextFunction
+    next: NextFunction,
 ): Promise<any> {
 ): Promise<any> {
     const parsedBody = authWithPasswordBodySchema.safeParse(req.body);
     const parsedBody = authWithPasswordBodySchema.safeParse(req.body);
 
 
@@ -40,8 +41,8 @@ export async function authWithPassword(
         return next(
         return next(
             createHttpError(
             createHttpError(
                 HttpCode.BAD_REQUEST,
                 HttpCode.BAD_REQUEST,
-                fromError(parsedBody.error).toString()
-            )
+                fromError(parsedBody.error).toString(),
+            ),
         );
         );
     }
     }
 
 
@@ -51,8 +52,8 @@ export async function authWithPassword(
         return next(
         return next(
             createHttpError(
             createHttpError(
                 HttpCode.BAD_REQUEST,
                 HttpCode.BAD_REQUEST,
-                fromError(parsedParams.error).toString()
-            )
+                fromError(parsedParams.error).toString(),
+            ),
         );
         );
     }
     }
 
 
@@ -65,7 +66,7 @@ export async function authWithPassword(
             .from(resources)
             .from(resources)
             .leftJoin(
             .leftJoin(
                 resourcePassword,
                 resourcePassword,
-                eq(resourcePassword.resourceId, resources.resourceId)
+                eq(resourcePassword.resourceId, resources.resourceId),
             )
             )
             .where(eq(resources.resourceId, resourceId))
             .where(eq(resources.resourceId, resourceId))
             .limit(1);
             .limit(1);
@@ -75,7 +76,10 @@ export async function authWithPassword(
 
 
         if (!resource) {
         if (!resource) {
             return next(
             return next(
-                createHttpError(HttpCode.BAD_REQUEST, "Resource does not exist")
+                createHttpError(
+                    HttpCode.BAD_REQUEST,
+                    "Resource does not exist",
+                ),
             );
             );
         }
         }
 
 
@@ -85,9 +89,9 @@ export async function authWithPassword(
                     HttpCode.UNAUTHORIZED,
                     HttpCode.UNAUTHORIZED,
                     createHttpError(
                     createHttpError(
                         HttpCode.BAD_REQUEST,
                         HttpCode.BAD_REQUEST,
-                        "Resource has no password protection"
-                    )
-                )
+                        "Resource has no password protection",
+                    ),
+                ),
             );
             );
         }
         }
 
 
@@ -99,11 +103,11 @@ export async function authWithPassword(
                 timeCost: 2,
                 timeCost: 2,
                 outputLen: 32,
                 outputLen: 32,
                 parallelism: 1,
                 parallelism: 1,
-            }
+            },
         );
         );
         if (!validPassword) {
         if (!validPassword) {
             return next(
             return next(
-                createHttpError(HttpCode.UNAUTHORIZED, "Incorrect password")
+                createHttpError(HttpCode.UNAUTHORIZED, "Incorrect password"),
             );
             );
         }
         }
 
 
@@ -127,18 +131,20 @@ export async function authWithPassword(
             token,
             token,
             passwordId: definedPassword.passwordId,
             passwordId: definedPassword.passwordId,
         });
         });
-        const secureCookie = resource.ssl;
-        const cookie = serializeResourceSessionCookie(
-            token,
-            resource.fullDomain,
-            secureCookie
-        );
-        res.appendHeader("Set-Cookie", cookie);
-
-        logger.debug(cookie); // remove after testing
-
-        return response<null>(res, {
-            data: null,
+        // const secureCookie = resource.ssl;
+        // const cookie = serializeResourceSessionCookie(
+        //     token,
+        //     resource.fullDomain,
+        //     secureCookie,
+        // );
+        // res.appendHeader("Set-Cookie", cookie);
+
+        // logger.debug(cookie); // remove after testing
+
+        return response<AuthWithPasswordResponse>(res, {
+            data: {
+                session: token,
+            },
             success: true,
             success: true,
             error: false,
             error: false,
             message: "Authenticated with resource successfully",
             message: "Authenticated with resource successfully",
@@ -148,8 +154,8 @@ export async function authWithPassword(
         return next(
         return next(
             createHttpError(
             createHttpError(
                 HttpCode.INTERNAL_SERVER_ERROR,
                 HttpCode.INTERNAL_SERVER_ERROR,
-                "Failed to authenticate with resource"
-            )
+                "Failed to authenticate with resource",
+            ),
         );
         );
     }
     }
 }
 }

+ 15 - 12
server/routers/resource/authWithPincode.ts

@@ -27,6 +27,7 @@ export const authWithPincodeParamsSchema = z.object({
 
 
 export type AuthWithPincodeResponse = {
 export type AuthWithPincodeResponse = {
     codeRequested?: boolean;
     codeRequested?: boolean;
+    session?: string;
 };
 };
 
 
 export async function authWithPincode(
 export async function authWithPincode(
@@ -126,18 +127,20 @@ export async function authWithPincode(
             token,
             token,
             pincodeId: definedPincode.pincodeId,
             pincodeId: definedPincode.pincodeId,
         });
         });
-        const secureCookie = resource.ssl;
-        const cookie = serializeResourceSessionCookie(
-            token,
-            resource.fullDomain,
-            secureCookie,
-        );
-        res.appendHeader("Set-Cookie", cookie);
-
-        logger.debug(cookie); // remove after testing
-
-        return response<null>(res, {
-            data: null,
+        // const secureCookie = resource.ssl;
+        // const cookie = serializeResourceSessionCookie(
+        //     token,
+        //     resource.fullDomain,
+        //     secureCookie,
+        // );
+        // res.appendHeader("Set-Cookie", cookie);
+
+        // logger.debug(cookie); // remove after testing
+
+        return response<AuthWithPincodeResponse>(res, {
+            data: {
+                session: token,
+            },
             success: true,
             success: true,
             error: false,
             error: false,
             message: "Authenticated with resource successfully",
             message: "Authenticated with resource successfully",

+ 12 - 7
server/routers/traefik/getTraefikConfig.ts

@@ -8,7 +8,7 @@ import config from "@server/config";
 
 
 export async function traefikConfigProvider(
 export async function traefikConfigProvider(
     _: Request,
     _: Request,
-    res: Response
+    res: Response,
 ): Promise<any> {
 ): Promise<any> {
     try {
     try {
         const all = await db
         const all = await db
@@ -16,18 +16,18 @@ export async function traefikConfigProvider(
             .from(schema.targets)
             .from(schema.targets)
             .innerJoin(
             .innerJoin(
                 schema.resources,
                 schema.resources,
-                eq(schema.targets.resourceId, schema.resources.resourceId)
+                eq(schema.targets.resourceId, schema.resources.resourceId),
             )
             )
             .innerJoin(
             .innerJoin(
                 schema.orgs,
                 schema.orgs,
-                eq(schema.resources.orgId, schema.orgs.orgId)
+                eq(schema.resources.orgId, schema.orgs.orgId),
             )
             )
             .where(
             .where(
                 and(
                 and(
                     eq(schema.targets.enabled, true),
                     eq(schema.targets.enabled, true),
                     isNotNull(schema.resources.subdomain),
                     isNotNull(schema.resources.subdomain),
-                    isNotNull(schema.orgs.domain)
-                )
+                    isNotNull(schema.orgs.domain),
+                ),
             );
             );
 
 
         if (!all.length) {
         if (!all.length) {
@@ -48,9 +48,14 @@ export async function traefikConfigProvider(
                         [badgerMiddlewareName]: {
                         [badgerMiddlewareName]: {
                             apiBaseUrl: new URL(
                             apiBaseUrl: new URL(
                                 "/api/v1",
                                 "/api/v1",
-                                `http://${config.server.internal_hostname}:${config.server.internal_port}`
+                                `http://${config.server.internal_hostname}:${config.server.internal_port}`,
                             ).href,
                             ).href,
-                            appBaseUrl: config.app.base_url,
+                            resourceSessionCookieName:
+                                config.badger.resource_session_cookie_name,
+                            userSessionCookieName:
+                                config.server.session_cookie_name,
+                            sessionQueryParameter:
+                                config.badger.session_query_parameter,
                         },
                         },
                     },
                     },
                 },
                 },

+ 5 - 4
src/api/cookies.ts

@@ -2,10 +2,11 @@ import { cookies } from "next/headers";
 
 
 export async function authCookieHeader() {
 export async function authCookieHeader() {
     const allCookies = await cookies();
     const allCookies = await cookies();
-    const sessionId = allCookies.get("session")?.value ?? null;
+    const cookieName = process.env.SESSION_COOKIE_NAME!;
+    const sessionId = allCookies.get(cookieName)?.value ?? null;
     return {
     return {
         headers: {
         headers: {
-            Cookie: `session=${sessionId}`
-        }
-    }
+            Cookie: `${cookieName}=${sessionId}`,
+        },
+    };
 }
 }

+ 35 - 8
src/app/auth/resource/[resourceId]/components/ResourceAuthPortal.tsx

@@ -37,6 +37,7 @@ import { AxiosResponse } from "axios";
 import { LoginResponse } from "@server/routers/auth";
 import { LoginResponse } from "@server/routers/auth";
 import ResourceAccessDenied from "./ResourceAccessDenied";
 import ResourceAccessDenied from "./ResourceAccessDenied";
 import LoginForm from "@app/components/LoginForm";
 import LoginForm from "@app/components/LoginForm";
+import { AuthWithPasswordResponse } from "@server/routers/resource";
 
 
 const pinSchema = z.object({
 const pinSchema = z.object({
     pin: z
     pin: z
@@ -62,6 +63,7 @@ type ResourceAuthPortalProps = {
         id: number;
         id: number;
     };
     };
     redirect: string;
     redirect: string;
+    queryParamName: string;
 };
 };
 
 
 export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
 export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
@@ -112,13 +114,29 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
         },
         },
     });
     });
 
 
+    function constructRedirect(redirect: string, token: string): string {
+        const redirectUrl = new URL(redirect);
+        redirectUrl.searchParams.delete(props.queryParamName);
+        redirectUrl.searchParams.append(props.queryParamName, token);
+        return redirectUrl.toString();
+    }
+
     const onPinSubmit = (values: z.infer<typeof pinSchema>) => {
     const onPinSubmit = (values: z.infer<typeof pinSchema>) => {
         setLoadingLogin(true);
         setLoadingLogin(true);
-        api.post(`/resource/${props.resource.id}/auth/pincode`, {
-            pincode: values.pin,
-        })
+        api.post<AxiosResponse<AuthWithPasswordResponse>>(
+            `/resource/${props.resource.id}/auth/pincode`,
+            {
+                pincode: values.pin,
+            },
+        )
             .then((res) => {
             .then((res) => {
-                window.location.href = props.redirect;
+                const session = res.data.data.session;
+                if (session) {
+                    window.location.href = constructRedirect(
+                        props.redirect,
+                        session,
+                    );
+                }
             })
             })
             .catch((e) => {
             .catch((e) => {
                 console.error(e);
                 console.error(e);
@@ -131,11 +149,20 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
 
 
     const onPasswordSubmit = (values: z.infer<typeof passwordSchema>) => {
     const onPasswordSubmit = (values: z.infer<typeof passwordSchema>) => {
         setLoadingLogin(true);
         setLoadingLogin(true);
-        api.post(`/resource/${props.resource.id}/auth/password`, {
-            password: values.password,
-        })
+        api.post<AxiosResponse<AuthWithPasswordResponse>>(
+            `/resource/${props.resource.id}/auth/password`,
+            {
+                password: values.password,
+            },
+        )
             .then((res) => {
             .then((res) => {
-                window.location.href = props.redirect;
+                const session = res.data.data.session;
+                if (session) {
+                    window.location.href = constructRedirect(
+                        props.redirect,
+                        session,
+                    );
+                }
             })
             })
             .catch((e) => {
             .catch((e) => {
                 console.error(e);
                 console.error(e);

+ 6 - 2
src/app/auth/resource/[resourceId]/page.tsx

@@ -14,7 +14,7 @@ import ResourceAccessDenied from "./components/ResourceAccessDenied";
 
 
 export default async function ResourceAuthPage(props: {
 export default async function ResourceAuthPage(props: {
     params: Promise<{ resourceId: number }>;
     params: Promise<{ resourceId: number }>;
-    searchParams: Promise<{ r: string }>;
+    searchParams: Promise<{ redirect: string }>;
 }) {
 }) {
     const params = await props.params;
     const params = await props.params;
     const searchParams = await props.searchParams;
     const searchParams = await props.searchParams;
@@ -44,9 +44,10 @@ export default async function ResourceAuthPage(props: {
     const hasAuth = authInfo.password || authInfo.pincode || authInfo.sso;
     const hasAuth = authInfo.password || authInfo.pincode || authInfo.sso;
     const isSSOOnly = authInfo.sso && !authInfo.password && !authInfo.pincode;
     const isSSOOnly = authInfo.sso && !authInfo.password && !authInfo.pincode;
 
 
-    const redirectUrl = searchParams.r || authInfo.url;
+    const redirectUrl = searchParams.redirect || authInfo.url;
 
 
     if (!hasAuth) {
     if (!hasAuth) {
+        // no authentication so always go straight to the resource
         redirect(redirectUrl);
         redirect(redirectUrl);
     }
     }
 
 
@@ -93,6 +94,9 @@ export default async function ResourceAuthPage(props: {
                         id: authInfo.resourceId,
                         id: authInfo.resourceId,
                     }}
                     }}
                     redirect={redirectUrl}
                     redirect={redirectUrl}
+                    queryParamName={
+                        process.env.RESOURCE_SESSION_QUERY_PARAM_NAME!
+                    }
                 />
                 />
             </div>
             </div>
         </>
         </>