I ran into a very similar problem. My use-case was this: I am building an app where users can have multiple "memberships" at different orgs. The current org_id
is stored in a separate cookie from the session token. When the user logs in, the following logic should apply:
- If they have no memberships, clear any
session_org_id
and redirect to Create Org
- If they have one membership, set the
session_org_id
and redirect to Home
- If they have multiple memberships, check the session org_id and if it matches one, redirect to Home, otherwise clear it and redirect to Choose Profile
Warning: NextJS App Router jargon ahead
This is very difficult to accomplish from within a server-side component, since server actions cannot be called from components... which is why my many many efforts to implement this logic IN choose-profile/page.tsx
component failed. What works, however, is to define a separate "post-auth" route handler that does this logic, since server actions CAN be called from route handers
// post-auth/route.ts
/// These server actions modify the session_org_id using import { cookies } from "next/headers";
import { clearSessionOrg, setSessionOrg } from "actions/setSessionOrg";
import { auth } from "auth";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
/// gets the user's memberships from the remote API server
import { getMemberships } from "ssr/get_memberships";
/// This function is responsible for checking a user's memberships;
/// setting or clearing the session org if necessary,
/// and then redirecting the user to the appropriate page
export async function GET() {
const cookieStore = cookies();
const session = await auth();
if (!session?.user) {
redirect("/sign-in");
}
const memberships = await getMemberships(cookieStore);
if (!memberships?.length) {
redirect("/create-org");
}
if (memberships?.length == 1) {
await setSessionOrg(memberships[0].org_id);
redirect("/client");
}
let sessionOrgId = cookieStore.get("versa.session_org_id")?.value;
if (sessionOrgId && memberships.find((m) => m.org_id === sessionOrgId)) {
redirect("/client");
} else {
await clearSessionOrg();
redirect("/choose-profile");
}
}
// actions/setSessionOrg.ts
"use server";
import { cookies } from "next/headers";
export const setSessionOrg = async (orgId: string) => {
"use server";
cookies().set("my-app.session_org_id", orgId, {
httpOnly: true,
sameSite: "none",
secure: true,
});
};
export const clearSessionOrg = async () => {
"use server";
cookies().delete("my-app.session_org_id");
};
Boom. Post login and anywhere I need to confirm a user's membership status (such as in my (authorized)
parent layout, I can redirect to "post-auth" instead of "choose-profile"