I have a problem with my next.js application.
I am using next.js 15 and NextAuth.
I can access my session in my /dashboard/accounts/page.tsx
, but not in my api route app/api/accounts/route.ts
.
Can someone explain why this is the case and give me a solution?
/dashboard/accounts/page.tsx
import { auth } from "@/lib/auth";
import { redirect } from "next/navigation";
import { checkPermissions } from "@/lib/permissions";
const Accounts = async () => {
const session = await auth();
if (!session || !checkPermissions(session.user, "view", "accounts")) {
redirect("/dashboard");
}
const accounts = await fetch("https://localhost:3000/api/accounts", {
method: "GET",
credentials: "include",
});
console.log(accounts);
=> outputs the session
app/api/accounts/route.ts
export async function GET(req: NextRequest) {
const session = await auth();
console.log("Session:", session);
=> outputs Session: null
src/lib/auth.ts
import { v4 as uuid } from "uuid";
import bcrypt from "bcrypt";
import { encode as defaultEncode } from "next-auth/jwt";
import db from "@/lib/db/db";
import { PrismaAdapter } from "@auth/prisma-adapter";
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import GitHub from "next-auth/providers/github";
import { schema } from "@/lib/schema";
import { User as PrismaUser, Role } from "@prisma/client";
const adapter = PrismaAdapter(db);
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter,
providers: [
GitHub,
Credentials({
credentials: {
email: {},
password: {},
},
authorize: async (credentials) => {
const validatedCredentials = schema.parse(credentials);
const user = await db.user.findFirst({
where: {
email: validatedCredentials.email,
},
});
if (!user) {
throw new Error("Invalid credentials.");
}
const passwordMatch =
user.password &&
(await bcryptpare(validatedCredentials.password, user.password));
if (!passwordMatch) {
throw new Error("Invalid credentials.");
}
return user;
},
}),
],
callbacks: {
async jwt({ token, account, user }) {
if (account?.provider === "credentials") {
token.credentials = true;
}
if (user) {
const prismaUser = user as PrismaUser & { role: string };
token.id = String(prismaUser.id);
token.name = prismaUser.name;
token.email = prismaUser.email;
token.picture = prismaUser.image;
token.role = prismaUser.role;
}
return token;
},
async session({ token, session }) {
if (token) {
session.user.id = token.id;
session.user.name = token.name;
session.user.image = token.picture;
session.user.role = token.role;
}
return session;
},
},
jwt: {
encode: async function (params) {
if (params.token?.credentials) {
const sessionToken = uuid();
if (!params.token.sub) {
throw new Error("No user ID found in token");
}
const createdSession = await adapter?.createSession?.({
sessionToken: sessionToken,
userId: params.token.sub,
expires: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
});
if (!createdSession) {
throw new Error("Failed to create session");
}
return sessionToken;
}
return defaultEncode(params);
},
},
});
src/lib/permissions.ts
const PERMISSIONS: Record<string, string[]> = {
ADMIN: ["view:accounts", "edit:accounts"],
};
export const checkPermissions = (
user: { role?: string } | null,
action: string,
resource: string
): boolean => {
if (!user || !user.role) return false;
const permissions = PERMISSIONS[user.role];
if (!permissions) return false;
return permissions.includes(`${action}:${resource}`);
};
For context: I want only admins to have access to the api route, so I want to check if the user is an admin by checking the session.
I have already tried to solve it via the middleware.ts
, but there is the same error, I cannot access the session.
can anyone help me to find the error or give me a hint as to why this could be?