K
Kinde3mo ago
Woet

Next.js - blocking error upon login when creating new organisations

I've been creating new organisations, which was working as expected, but with the latest organisations, my support user is running into issues with the Kinde SDK after logging into such an organisation, even though I haven't made any changes compared to what was previously working. While this is still working correctly for previous organisations, it's blocking me from onboarding new customers at the moment so quite severe for my side and I hope somebody can help me figure out what might be going wrong.
No description
No description
22 Replies
Woet
WoetOP3mo ago
This is the code in my middleware
Yoshify
Yoshify3mo ago
Hi @Woet , what version of the SDK are you using (and have you upgraded recently?)
Woet
WoetOP3mo ago
I'm currently on "@kinde-oss/kinde-auth-nextjs": "^2.4.6",
Yoshify
Yoshify3mo ago
This might be an odd request but could you try downgrading to 2.4.5 and see if you continue to get the error? The reason I ask is because I believe there may be a bug in version 2.4.6 of the SDK that could be causing this - I haven't been able to replicate your issue specifically, but I can replicate null ID tokens in middleware (which could lead to the error you're experiencing)
Woet
WoetOP3mo ago
I'll take a look
Yoshify
Yoshify3mo ago
Let me know how you go, I'll be around to help 🙂
Woet
WoetOP3mo ago
Still getting the same error unfortunately:
No description
Yoshify
Yoshify3mo ago
Okay, so that leaves us with 2 possibilities here - the ID token is null, or, somehow, the user has a null family name. Let’s try the easy one first - in the users profile on the Kinde admin dashboard, do they have a family name set? If not can we set it to something temporary?
Woet
WoetOP3mo ago
That was idd my first idea; so I split the name in two
No description
Woet
WoetOP3mo ago
But doesn't seem to quite solve the issue yet
Yoshify
Yoshify3mo ago
Okay great! In the middleware, can we try doing:
import {getKindeServerSession} from "@kinde-oss/kinde-auth-nextjs/server";

const {isAuthenticated} = getKindeServerSession();
const isUserAuthenticated = await isAuthenticated();
console.log('Authed?', isUserAuthenticated);
import {getKindeServerSession} from "@kinde-oss/kinde-auth-nextjs/server";

const {isAuthenticated} = getKindeServerSession();
const isUserAuthenticated = await isAuthenticated();
console.log('Authed?', isUserAuthenticated);
Just to confirm the user is definitely authenticated? If that returns true, I'd like to see if we're getting any ID token at all:
import {getKindeServerSession} from "@kinde-oss/kinde-auth-nextjs/server";

const {getIdTokenRaw} = getKindeServerSession();
const idToken = await getIdTokenRaw();
console.log('Token:', idToken);
import {getKindeServerSession} from "@kinde-oss/kinde-auth-nextjs/server";

const {getIdTokenRaw} = getKindeServerSession();
const idToken = await getIdTokenRaw();
console.log('Token:', idToken);
Woet
WoetOP3mo ago
Logging things is a little bit of a hassle right now though, cause I only have the issue with my production environment Haven't been able to reproduce it yet when working with my development environment on Kinde I also have some auth checks in the layout of the project, could this be causing any conflicts: ´´´
import { cookies } from "next/headers";

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";

....

import { syncCachedAppUser } from "@/features/authentication/actions/syncAppUser";

export default async function FirmLayout({
children,
}: {
children: React.ReactNode;
}) {
const cookieStore = cookies();
const defaultOpen = cookieStore.get("sidebar:state")?.value === "true";

const {
getBooleanFlag,
getClaim,
isAuthenticated,
getUser,
getOrganization,
getPermissions,
} = getKindeServerSession();

const userOrganizationsClaim = await getClaim("organizations", "id_token");
const userOrganizations = (userOrganizationsClaim?.value ?? []) as {
id: string;
name: string;
}[];

const loggedIn = await isAuthenticated();
const kindeUser = await getUser();
const userOrganization = await getOrganization();
const orgCode = userOrganization?.orgCode;
const permissionsInfo = await getPermissions();
const permissions = permissionsInfo?.permissions ?? [];

// Check if user is logged in and belongs to an organization
if (!loggedIn || !orgCode) {
console.log("You are not authenticated");

redirect("/login");
}

// Check if user exists on Kinde
if (!kindeUser?.id || !kindeUser?.email) {
console.log("No valid user found");

redirect("/login");
}

// Sort the organizations by name
userOrganizations.sort((a, b) => a.name.localeCompare(b.name));

const mvpFeatureFlag = (await getBooleanFlag("mvp_features", true)) ?? false;
const dataWarehouseFeatureFlag =
(await getBooleanFlag("data_warehouse", true)) ?? false;

const { user } = await syncCachedAppUser(kindeUser, orgCode, permissions);

if (!user) {
redirect("/login");
}

return (
<>
...
</>
);
}
import { cookies } from "next/headers";

import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
import { redirect } from "next/navigation";

....

import { syncCachedAppUser } from "@/features/authentication/actions/syncAppUser";

export default async function FirmLayout({
children,
}: {
children: React.ReactNode;
}) {
const cookieStore = cookies();
const defaultOpen = cookieStore.get("sidebar:state")?.value === "true";

const {
getBooleanFlag,
getClaim,
isAuthenticated,
getUser,
getOrganization,
getPermissions,
} = getKindeServerSession();

const userOrganizationsClaim = await getClaim("organizations", "id_token");
const userOrganizations = (userOrganizationsClaim?.value ?? []) as {
id: string;
name: string;
}[];

const loggedIn = await isAuthenticated();
const kindeUser = await getUser();
const userOrganization = await getOrganization();
const orgCode = userOrganization?.orgCode;
const permissionsInfo = await getPermissions();
const permissions = permissionsInfo?.permissions ?? [];

// Check if user is logged in and belongs to an organization
if (!loggedIn || !orgCode) {
console.log("You are not authenticated");

redirect("/login");
}

// Check if user exists on Kinde
if (!kindeUser?.id || !kindeUser?.email) {
console.log("No valid user found");

redirect("/login");
}

// Sort the organizations by name
userOrganizations.sort((a, b) => a.name.localeCompare(b.name));

const mvpFeatureFlag = (await getBooleanFlag("mvp_features", true)) ?? false;
const dataWarehouseFeatureFlag =
(await getBooleanFlag("data_warehouse", true)) ?? false;

const { user } = await syncCachedAppUser(kindeUser, orgCode, permissions);

if (!user) {
redirect("/login");
}

return (
<>
...
</>
);
}
So my auth in the middleware is a bit redundant?
Yoshify
Yoshify3mo ago
I don't believe so - if this is your root layout though, your middleware may be a little redundant. Understood RE: logging, build times suck - I have tried to replicate it on Vercel and locally to no avail unfortunately (though I'm not using your CSP headers, but I don't think that would be the cause of issue here) - unfortunately it's hard to move much further without logging to narrow down the cause. All I can get from the error returned right now is that the error appears to be happening on this line of the source, which means the idTokenValue defined on line 39 is for some reason in your case null.
GitHub
kinde-auth-nextjs/src/authMiddleware/authMiddleware.ts at c65d26508...
Kinde NextJS SDK - authentication for server rendered apps - kinde-oss/kinde-auth-nextjs
Yoshify
Yoshify3mo ago
On that note, these are also redundant in your middleware options:
...
publicPaths: [],
isAuthorized: ({ token }: { token: KindeAccessToken }) => {
return true;
},
...
...
publicPaths: [],
isAuthorized: ({ token }: { token: KindeAccessToken }) => {
return true;
},
...
public paths defaults to nothing by default, and isAuthorized will default to true, so if these aren't in use you can omit them 🙂 (unrelated to the bug, just thought I'd let you know)
Woet
WoetOP3mo ago
I've removed the middleware and tried only authenticating from the root layout, but the issue persists. I've also tried linking another user to the organisation and this works as expected. Considering it also only crashes when the support user is added on specific organisations, it seems it's throwing an error on the missing last name for some orgs, but not for others.
No description
Woet
WoetOP3mo ago
I used to not give the user a last name I think that's still causing some issues somewhere
Woet
WoetOP3mo ago
@Yoshify sorry, I had to deliver 3 new customer organisations for tomorrow, so worked around this issue for now with another account. I've setup my dev so I can already log the issues there and it does indeed seem that it already goes wrong with the isAuthenticated() check
No description
Yoshify
Yoshify3mo ago
@Woet Understood - and this only happens with this Finibase Support user you've created? No other user causes this problem?
Woet
WoetOP3mo ago
@Yoshify yeah, I've also contacted Kinde support. Looks like the problem was due the organizations array option enabled in the ID token. It only with the support user because it had a lot of organizations linked (20+) and this scale apparently causes an issue with the ID token at the moment (I enabled it to develop a tenant switcher in my app). I've disabled this option and working as normal again now.
No description
Yoshify
Yoshify3mo ago
Thanks for sharing @Woet - I wasn’t aware of this limitation either (I might actually run into this same issue in my app soon…) Hopefully it’s something the team can fix soon!
Woet
WoetOP3mo ago
Hope so! 🤞 But thanks for the help @Yoshify, appreciate it!
Yoshify
Yoshify3mo ago
Any time mate, it's what I'm here for! Happy building 👏

Did you find this page helpful?