-
Notifications
You must be signed in to change notification settings - Fork 382
-
Hello everyone,
We're implementing a micro-frontend architecture with module federation in our company and now require a JavaScript server for SSR features. We've been exploring Modern.js due to its excellent support for module federation, and I've found it straightforward to use. However, I've run into a challenge while testing server-side authentication using the Microsoft authentication library.
Problem:
I'm having trouble maintaining session values like sessionId or user tokens. Despite setting up most of the logic correctly, these session values seem to be lost between requests. I've tried using hono-sessions for session management, but the session data appears to be wiped out between requests.
Code Overview:
Here's a sample of the setup:
import { defineServerConfig } from "@modern-js/server-runtime"; import { ConfidentialClientApplication, Configuration, CryptoProvider, } from "@azure/msal-node"; import { sessionMiddleware, CookieStore } from "hono-sessions"; import msalCachePlugin from "./cachePlugin"; const store = new CookieStore(); // scopes const scopes = ["email", "openid"]; const msalConfig = { auth: { clientId: "<client-id>", authority: "<authority>", clientSecret: "<clientSecret>", scopes, knownAuthorities: ["<knownAuthorities>"], responseMode: "form_post", }, cache: { cachePlugin: msalCachePlugin("./data/msal.cache.json"), }, } as Configuration; const redirectUri = "<redirectUri>"; const pca = new ConfidentialClientApplication(msalConfig); const cryptoProvider = new CryptoProvider(); const session = sessionMiddleware({ store, encryptionKey: "password_at_least_32_characters_long", // Required for CookieStore, recommended for others. // You can also supply a function instead of a plain string // encryptionKey: () => 'function_that_returns_a_long_string' expireAfterSeconds: 900, // Expire session after 15 minutes of inactivity autoExtendExpiration: true, // Extend the session expiration time automatically. Defaults to true cookieOptions: { sameSite: "Lax", // Recommended for basic CSRF protection in modern browsers path: "/", // Required for this library to work properly httpOnly: true, // Recommended to avoid XSS attacks }, }); export default defineServerConfig({ middlewares: [ { name: "sessions", handler: session as any, before: ["auth-middleware"] }, { name: "auth-middleware", handler: async (c, next) => { const session = c.get("session"); const { code } = await c.req.parseBody(); console.log("account", session.get("account")); const account = await pca .getTokenCache() .getAccountByHomeId(session.get("account")?.homeAccountId); console.log("getTokenCache", account); if (!code && !session.get("sessionId") && !account) { const sessionId = cryptoProvider.createNewGuid(); session.set("sessionId", sessionId); console.log("session-setter", sessionId); console.log("auth-middleware", "sessionId", session.get("sessionId")); const r = await pca.getAuthCodeUrl({ scopes, redirectUri, extraQueryParameters: { nativebroker: "1", }, state: session.get("sessionId"), responseMode: "form_post", }); return c.redirect(r); } await next(); }, }, { name: "auth-middleware-redirect", path: "/redirect-login/", method: "post", handler: async (c, next) => { const { code, state } = await c.req.parseBody(); const session = c.get("session"); if (state) { if (state === session.get("sessionId")) { const tokenRequest = { code: code as string, scopes, redirectUri, enableSpaAuthorizationCode: true, tokenBodyParameters: { return_spa_code: "1", }, }; const token = await pca.acquireTokenByCode(tokenRequest); session.set("account", token.account); return c.redirect("/"); } } return c.json({ error: "Error", }); }, }, ], renderMiddlewares: [], plugins: [], });
Flow Description:
- Initial Access: When a user accesses any page, middleware checks if they are authenticated.
- Redirection: If not authenticated, the user is redirected to the identity provider's login page with a sessionId in the state parameter.
- Post-authentication: After logging in, the user is redirected back to our app via a form post request, which includes a code for token acquisition and the state.
- State Validation: Before requesting the token, the state must match the sessionId. However, upon redirection, the sessionId becomes null, indicating the session data is lost.
Without session logic, the app can authenticate successfully and store the token in a custom cache. I'm looking for insights or advice on what might be wrong or missing in my current setup.
Any help or suggestions would be greatly appreciated!
Thank you,
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment
-
The session here should be framework-independent. The issue is initially confirmed to be that sameSite: "Lax" prevents cross-origin POST requests from including cookies. You can try configuring it as sameSite: "None" and see if that works.
Beta Was this translation helpful? Give feedback.