{"version":3,"file":"auth.mjs","names":["buildUser","getAppSession","redirect","location","Response","status","headers","Location","resolveRedirectUri","origin","sanitizeReturnTo","value","startsWith","handleLogin","Promise","getRequestUrl","url","returnTo","searchParams","get","cryptoProvider","buildAuthCodeUrl","verifier","challenge","generatePkceCodes","state","createNewGuid","session","update","pkceVerifier","authUrl","redirectUri","codeChallenge","handleCallback","expectedState","data","error","clear","encodeURIComponent","code","exchangeCodeForSession","refreshToken","claims","codeVerifier","user","undefined","message","Error","console","handleLogout","buildLogoutUrl"],"sources":["../src/lib/auth/authHandlers.ts"],"sourcesContent":["import { buildUser } from \"~/lib/utils\";\nimport { getAppSession } from \"./session\";\n\n// These handlers run only as server route handlers, so their server-only deps are\n// imported dynamically to keep them out of the client bundle: `entra` pulls in\n// `@azure/msal-node`, and `@tanstack/react-start/server` pulls in the SSR renderer\n// (`react-dom/server`).\n\n/**\n * Server-side handlers for the OAuth2 Authorization Code (PKCE) flow. They are\n * mounted by thin route files (`/auth/login`, `/auth/callback`, `/auth/logout`)\n * in the consuming app and drive the full server-side Entra login — the browser\n * never loads an auth library.\n */\n\nconst redirect = (location: string): Response =>\n  new Response(null, { status: 302, headers: { Location: location } });\n\n/** The OAuth redirect URI, derived from the request origin. */\nconst resolveRedirectUri = (origin: string): string => `${origin}/auth/callback`;\n\n/** Only same-origin paths are allowed, so `returnTo` cannot become an open redirect. */\nconst sanitizeReturnTo = (value: string | null): string =>\n  value?.startsWith(\"/\") && !value.startsWith(\"//\") ? value : \"/\";\n\n/** GET /auth/login — start the flow: stash PKCE + state, redirect to Entra. */\nexport async function handleLogin(): Promise<Response> {\n  const { getRequestUrl } = await import(\"@tanstack/react-start/server\");\n  const url = getRequestUrl();\n  const returnTo = sanitizeReturnTo(url.searchParams.get(\"returnTo\"));\n\n  const { cryptoProvider, buildAuthCodeUrl } = await import(\"./entra\");\n  const { verifier, challenge } = await cryptoProvider.generatePkceCodes();\n  const state = cryptoProvider.createNewGuid();\n\n  const session = await getAppSession();\n  await session.update({ pkceVerifier: verifier, state, returnTo });\n\n  const authUrl = await buildAuthCodeUrl({\n    redirectUri: resolveRedirectUri(url.origin),\n    state,\n    codeChallenge: challenge,\n  });\n  return redirect(authUrl);\n}\n\n/** GET /auth/callback — finish the flow: validate state, exchange code, set session. */\nexport async function handleCallback(): Promise<Response> {\n  const { getRequestUrl } = await import(\"@tanstack/react-start/server\");\n  const url = getRequestUrl();\n  const session = await getAppSession();\n  const { pkceVerifier, state: expectedState, returnTo = \"/\" } = session.data;\n\n  const error = url.searchParams.get(\"error\");\n  if (error) {\n    await session.clear();\n    return redirect(`/?auth_error=${encodeURIComponent(error)}`);\n  }\n\n  const code = url.searchParams.get(\"code\");\n  const state = url.searchParams.get(\"state\");\n  if (!code || !state || !pkceVerifier || state !== expectedState) {\n    await session.clear();\n    return redirect(\"/?auth_error=invalid_state\");\n  }\n\n  try {\n    const { exchangeCodeForSession } = await import(\"./entra\");\n    const { refreshToken, claims } = await exchangeCodeForSession({\n      code,\n      redirectUri: resolveRedirectUri(url.origin),\n      codeVerifier: pkceVerifier,\n    });\n\n    // Persist the refresh token + trimmed user; drop the spent transient values.\n    await session.update({\n      refreshToken,\n      user: buildUser(claims),\n      pkceVerifier: undefined,\n      state: undefined,\n      returnTo: undefined,\n    });\n\n    return redirect(returnTo);\n  } catch (error) {\n    const message = error instanceof Error ? error.message : \"token_exchange_failed\";\n    console.error(\"[auth] code exchange failed:\", message);\n    await session.clear();\n    return redirect(`/?auth_error=${encodeURIComponent(message)}`);\n  }\n}\n\n/** GET /auth/logout — clear the local session and sign out of the Entra session. */\nexport async function handleLogout(): Promise<Response> {\n  const { getRequestUrl } = await import(\"@tanstack/react-start/server\");\n  const url = getRequestUrl();\n  const session = await getAppSession();\n  await session.clear();\n  const { buildLogoutUrl } = await import(\"./entra\");\n  return redirect(buildLogoutUrl(`${url.origin}/`));\n}\n"],"mappings":";;;;;;;;;AAeA,MAAME,YAAYC,aAChB,IAAIC,SAAS,MAAM;CAAEC,QAAQ;CAAKC,SAAS,EAAEC,UAAUJ,SAAS;AAAE,CAAC;;AAGrE,MAAMK,sBAAsBC,WAA2B,GAAGA,OAAM;;AAGhE,MAAMC,oBAAoBC,UACxBA,OAAOC,WAAW,GAAG,KAAK,CAACD,MAAMC,WAAW,IAAI,IAAID,QAAQ;;AAG9D,eAAsBE,cAAiC;CACrD,MAAM,EAAEE,kBAAkB,MAAM,OAAO;CACvC,MAAMC,MAAMD,cAAc;CAC1B,MAAME,WAAWP,iBAAiBM,IAAIE,aAAaC,IAAI,UAAU,CAAC;CAElE,MAAM,EAAEC,gBAAgBC,qBAAqB,MAAM,OAAO;CAC1D,MAAM,EAAEC,UAAUC,cAAc,MAAMH,eAAeI,kBAAkB;CACvE,MAAMC,QAAQL,eAAeM,cAAc;CAG3C,OAAMC,MADgB1B,cAAc,EAAA,CACtB2B,OAAO;EAAEC,cAAcP;EAAUG;EAAOR;CAAS,CAAC;CAEhE,MAAMa,UAAU,MAAMT,iBAAiB;EACrCU,aAAavB,mBAAmBQ,IAAIP,MAAM;EAC1CgB;EACAO,eAAeT;CACjB,CAAC;CACD,OAAOrB,SAAS4B,OAAO;AACzB;;AAGA,eAAsBG,iBAAoC;CACxD,MAAM,EAAElB,kBAAkB,MAAM,OAAO;CACvC,MAAMC,MAAMD,cAAc;CAC1B,MAAMY,UAAU,MAAM1B,cAAc;CACpC,MAAM,EAAE4B,cAAcJ,OAAOS,eAAejB,WAAW,QAAQU,QAAQQ;CAEvE,MAAMC,QAAQpB,IAAIE,aAAaC,IAAI,OAAO;CAC1C,IAAIiB,OAAO;EACT,MAAMT,QAAQU,MAAM;EACpB,OAAOnC,SAAS,gBAAgBoC,mBAAmBF,KAAK,GAAG;CAC7D;CAEA,MAAMG,OAAOvB,IAAIE,aAAaC,IAAI,MAAM;CACxC,MAAMM,QAAQT,IAAIE,aAAaC,IAAI,OAAO;CAC1C,IAAI,CAACoB,QAAQ,CAACd,SAAS,CAACI,gBAAgBJ,UAAUS,eAAe;EAC/D,MAAMP,QAAQU,MAAM;EACpB,OAAOnC,SAAS,4BAA4B;CAC9C;CAEA,IAAI;EACF,MAAM,EAAEsC,2BAA2B,MAAM,OAAO;EAChD,MAAM,EAAEC,cAAcC,WAAW,MAAMF,uBAAuB;GAC5DD;GACAR,aAAavB,mBAAmBQ,IAAIP,MAAM;GAC1CkC,cAAcd;EAChB,CAAC;EAGD,MAAMF,QAAQC,OAAO;GACnBa;GACAG,MAAM5C,UAAU0C,MAAM;GACtBb,cAAcgB,KAAAA;GACdpB,OAAOoB,KAAAA;GACP5B,UAAU4B,KAAAA;EACZ,CAAC;EAED,OAAO3C,SAASe,QAAQ;CAC1B,SAASmB,OAAO;EACd,MAAMU,UAAUV,iBAAiBW,QAAQX,MAAMU,UAAU;EACzDE,QAAQZ,MAAM,gCAAgCU,OAAO;EACrD,MAAMnB,QAAQU,MAAM;EACpB,OAAOnC,SAAS,gBAAgBoC,mBAAmBQ,OAAO,GAAG;CAC/D;AACF;;AAGA,eAAsBG,eAAkC;CACtD,MAAM,EAAElC,kBAAkB,MAAM,OAAO;CACvC,MAAMC,MAAMD,cAAc;CAE1B,OAAMY,MADgB1B,cAAc,EAAA,CACtBoC,MAAM;CACpB,MAAM,EAAEa,mBAAmB,MAAM,OAAO;CACxC,OAAOhD,SAASgD,eAAe,GAAGlC,IAAIP,OAAM,EAAG,CAAC;AAClD"}