diff --git a/login/apps/login/src/lib/saml.ts b/login/apps/login/src/lib/saml.ts index e1b5f4c08..3bbc1cdca 100644 --- a/login/apps/login/src/lib/saml.ts +++ b/login/apps/login/src/lib/saml.ts @@ -25,29 +25,70 @@ export async function getSAMLFormUID() { export async function setSAMLFormCookie(value: string): Promise { const cookiesList = await cookies(); - const uid = await getSAMLFormUID(); - await cookiesList.set({ - name: uid, - value: value, - httpOnly: true, - path: "/", - maxAge: 5 * 60, // 5 minutes - }); + try { + // Check cookie size limits (typical limit is 4KB) + if (value.length > 4000) { + console.warn( + `SAML form cookie value is large (${value.length} characters), may exceed browser limits`, + ); + } - return uid; + // Log the attempt + console.log( + `Setting SAML form cookie with uid: ${uid}, value length: ${value.length}`, + ); + + await cookiesList.set({ + name: uid, + value: value, + httpOnly: true, + path: "/", + maxAge: 5 * 60, // 5 minutes + }); + + // Note: We can't reliably verify immediately due to Next.js cookies API behavior + // Instead, we'll rely on the getSAMLFormCookie function to detect failures + console.log(`Successfully set SAML form cookie with uid: ${uid}`); + + return uid; + } catch (error) { + console.error(`Failed to set SAML form cookie with uid: ${uid}`, { + error, + valueLength: value.length, + uid, + }); + throw new Error( + `Failed to set SAML form cookie: ${error instanceof Error ? error.message : String(error)}`, + ); + } } export async function getSAMLFormCookie(uid: string): Promise { const cookiesList = await cookies(); - const cookie = cookiesList.get(uid); - if (!cookie || !cookie.value) { + try { + const cookie = cookiesList.get(uid); + + if (!cookie) { + console.warn(`SAML form cookie not found for uid: ${uid}`); + return null; + } + + if (!cookie.value) { + console.warn(`SAML form cookie found but empty value for uid: ${uid}`); + return null; + } + + console.log( + `Successfully retrieved SAML form cookie for uid: ${uid}, value length: ${cookie.value.length}`, + ); + return cookie.value; + } catch (error) { + console.error(`Error retrieving SAML form cookie for uid: ${uid}`, error); return null; } - - return cookie.value; } export async function loginWithSAMLAndSession({ diff --git a/login/apps/login/src/lib/zitadel.ts b/login/apps/login/src/lib/zitadel.ts index d8b4e5fb5..59b3c2801 100644 --- a/login/apps/login/src/lib/zitadel.ts +++ b/login/apps/login/src/lib/zitadel.ts @@ -989,10 +989,72 @@ export async function startIdentityProviderFlow({ const formData: FormData = resp.nextStep.value; const redirectUrl = "/saml-post"; - const dataId = await setSAMLFormCookie(JSON.stringify(formData.fields)); - const params = new URLSearchParams({ url: formData.url, id: dataId }); + try { + // Log the attempt with structure inspection + console.log("Attempting to stringify formData.fields:", { + fields: formData.fields, + fieldsType: typeof formData.fields, + fieldsKeys: Object.keys(formData.fields || {}), + fieldsEntries: Object.entries(formData.fields || {}), + }); - return `${redirectUrl}?${params.toString()}`; + const stringifiedFields = JSON.stringify(formData.fields); + console.log( + "Successfully stringified formData.fields, length:", + stringifiedFields.length, + ); + + // Check cookie size limits (typical limit is 4KB) + if (stringifiedFields.length > 4000) { + console.warn( + `SAML form cookie value is large (${stringifiedFields.length} characters), may exceed browser limits`, + ); + } + + const dataId = await setSAMLFormCookie(stringifiedFields); + const params = new URLSearchParams({ url: formData.url, id: dataId }); + + return `${redirectUrl}?${params.toString()}`; + } catch (stringifyError) { + console.error("Failed to stringify formData.fields:", { + error: stringifyError, + formDataFields: formData.fields, + formDataUrl: formData.url, + fieldsType: typeof formData.fields, + fieldsConstructor: formData.fields?.constructor?.name, + }); + + // Try to create a safe serialization by converting to plain object + try { + const safeFields: Record = {}; + const fieldsObj = formData.fields || {}; + + // Convert each field to a string if it's not already + for (const [key, value] of Object.entries(fieldsObj)) { + safeFields[key] = + typeof value === "string" ? value : String(value); + } + + console.log( + "Using safe serialization for formData.fields:", + safeFields, + ); + + const safeStringified = JSON.stringify(safeFields); + const dataId = await setSAMLFormCookie(safeStringified); + const params = new URLSearchParams({ + url: formData.url, + id: dataId, + }); + + return `${redirectUrl}?${params.toString()}`; + } catch (fallbackError) { + console.error("Safe serialization also failed:", fallbackError); + throw new Error( + `Failed to serialize SAML form data: ${stringifyError instanceof Error ? stringifyError.message : String(stringifyError)}`, + ); + } + } } else { return null; }