Reputation: 539
I've inherited working on a next.js app and have run into a quite frustrating scenario. After logging into the app, the session (iron-session) is stored in a cookie for authentication/session validation made on each subsequent server call. I check the cookie using middleware, and if the session is valid, then it allows the user to proceed within the app. Session expires/is invalid, and it redirects to the homepage. Nothing crazy. Works well on desktop (localhost) and in deployment (google app engine - standard env).
Curiously, when I access the deployed app via mobile (iPhone 15 using google Chrome or Safari app), when I log into the app, the login is successful, but then on the first call for app data, i'm logging that there are no cookies and I get booted back to the homepage. Only on mobile.
I've tried changing around cookie settings like "httpOnly", "secure", "sameSite" (tried, strict, lax, none), etc. and can't get the cookies to be there on mobile only (works on desktop).
I thought it might be something to do with my middleware, so I commented out all of the middleware logic, and now have a somewhat stripped down routing logic, and I'm fairly convinced it has to do with cookies and/or some interaction with the session in tRPC. When I log the session just before verification, there is no session being stored at all (the session is coming from being stored in the TRPC create context). Again, this is only on mobile. When I do the exact same route pattern ("/", "/login", "/dashboard") on desktop (dev and prod), it works just fine.
I can't find anything about persistence of tRPC context or cookies on mobile - so I'm turning to the hivemind for suggestions and ideas.
Relevant tools being used: Next.js, routing with TRPC (I think this might be causing some of the issue), Firebase (auth), Google App Engine - Standard Environment (hosting), Iron-Session (cookies/session management).
Relevant code:
TRPC context:
export type CreateContextOptions = Partial<CreateNextContextOptions> & {
cookies(): CookieStore;
};
export async function createContext(opts: CreateContextOptions) {
const session = await getSession(opts.cookies());
console.log("ctx creation session", session); //this logs the session created on login, but is an empty object on the next call to the server
const services: DomainServices = {
foo: barService(),
};
return {
services,
session,
};
}
Get session code
export async function getSession(cookieStore: CookieStore) {
const session = await getIronSession<AuthSession>(cookieStore, sessionOptions);
return session;
}
Middleware procedure for protecting server actions and routes
export const protectedMiddleware = procedure.use(async function isAuthenticated({ ctx: { services, session }, next }) {
console.log("session inside isAuthenticated", session); //This shows session as an empty object on mobile (on second request after sucessful login), but not on desktop (desktop it shows the session object with cookies)
const { identity, isSessionValid } = await services.account.verifySession(session);
// .verifySession extracts the cookies from the session and verifies the cookies
return next({
ctx: {
identity,
},
});
});
procedure comes from the initilization of trpc
import { initTRPC } from "@trpc/server";
import type { TRPCContext } from "./context";
export const { mergeRouters, procedure, router } = initTRPC
.context<TRPCContext>()
.create();
I'm happy to add any additional snippets of code or information if needed.
Upvotes: 0
Views: 47