NextJS API endpoint - verify token

Hello, First off, im currently studying front-end development, take this as a warning as this might be a "noob" question! Im currently setting up my API for my NextJs application, using kinde as authentication. As ive developed this i have used NextJS server-actions to check authentication for user and checked the role. Now that im trying to implement this on the API route endpoints (/api) i can no longer check the auth status with "getKindeServerSession", im not really sure why but if I for example try getUser im getting "null". As this issue showed up i have tried looking other ways for authenticate. I have set up the SDK for management API on my NextJS API but have not really found any solution. I have noticed that my requests to the API does not include any "cookie", for a token to check. Im thinking that the middleware used with NextJS + kindeauth is messing this up as the matcher is exluding "api" routes. Hopefully this is very easy for someone to explain, appreciate the support, thanks in advance!
8 Replies
Yoshify
Yoshifyβ€’2d ago
πŸ‘‹ could you please share what your middleware.ts file looks like, as well as your route handler? πŸ™‚ If you could also share how you're calling this route handler that'd be good too!
moggelitalanya
moggelitalanyaOPβ€’2d ago
middleware.ts import { withAuth } from "@kinde-oss/kinde-auth-nextjs/middleware"; export default withAuth(async function middleware() {}, { isReturnToCurrentPage: true, }); export const config = { matcher: [ "/((?!api|_next/static|_next/image|auth|favicon.ico|robots.txt|images|login|$).*)", ], }; One of my endpoints, route.ts (domain.xx/api/tasks), keeping it simple for this example, also added example desired functionallity: export async function GET(req: Request) { try { //more complex to check role etc later const { isAuthenticated } = getKindeServerSession(); const isAuth = await isAuthenticated(); if(!isAuth){ return NextResponse.json( { error: "Failed to get tasks" }, { status: 500 }, ); } const data = await db.task.findMany({}); return NextResponse.json(data); } catch (error) { console.log(error); } } function for calling and returning data (nextjs server-action): export const getAllTasks = async () => { try { const response = await fetch( ${process.env.NEXT_PUBLIC_API_URL}/api/tasks, { credentials: "include", headers: { "Content-Type": "application/json", }, }, ); const data = await response.json(); return data; } catch (error) { return { success: false, error: error }; } }; Hopefully this helps. addition, ive tried out adding the "getIdTokenRaw" to the request-header and can get the token from the user from there, how would i then validate this token to Kinde. Just an idea.
Yoshify
Yoshifyβ€’2d ago
Internal fetching inside a server action is a bit of an anti-pattern in NextJS - This is primarily because data fetching by HTTP standards should be a GET request (and you get all the goodies associated with that, like caching!) By using a server action, you're converting this into a POST request, which is not recommended. Internal server<->server fetches in NextJS won't include cookies, which is why you're probably seeing this issue. Where you make your fetch request, you can carry to cookies over like so:
import { cookies } from "next/headers";

const doDataFetchingStuff = async () => {
const cookieStore = await cookies();
const response = await fetch(SOME_URL, {
headers: { Cookie: cookieStore.toString() },
});
}
import { cookies } from "next/headers";

const doDataFetchingStuff = async () => {
const cookieStore = await cookies();
const response = await fetch(SOME_URL, {
headers: { Cookie: cookieStore.toString() },
});
}
This is a band-aid though - the real fix to this problem is doing away with your fetch endpoint altogether and communicating with your database in your page/layout/server component and passing the data down as props to client components. By default in Next, layouts, pages, and components are React Server Components and can talk to your backend directly unless specifically marked otherwise with the 'use client' directive at the top of a file. An example of what this could look like: Your page.tsx:
// no need for 'use server' directive here,
// it's a server component by default.
// note the use of 'async' - server components can // be asynchronous
export default async function DashboardPage() {
const posts = await db.query.posts.findMany();
return (
<PostsList posts={posts}/>
)
}
// no need for 'use server' directive here,
// it's a server component by default.
// note the use of 'async' - server components can // be asynchronous
export default async function DashboardPage() {
const posts = await db.query.posts.findMany();
return (
<PostsList posts={posts}/>
)
}
// this is my PostsList component in a separate file

'use client'

export const PostsList = ({posts}: {posts: Post[]}) => {
return posts.map((post, index) =>
<div>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
)
}
// this is my PostsList component in a separate file

'use client'

export const PostsList = ({posts}: {posts: Post[]}) => {
return posts.map((post, index) =>
<div>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
)
}
Pseudo-code, but it should help direct you
moggelitalanya
moggelitalanyaOPβ€’2d ago
I see, that makes sense, i was not totally aware that there is a difference in "server-action" and "server-component", if i understood that right. I noticed that i did not mention that im aiming on using this API for other platforms later (example react native), meaning im aiming on making the DB fetch on the API. I got reminded of that due to your example fetching the DB in server-component. Does this makes sense? Thank you so far, really appreciate it.
Yoshify
Yoshifyβ€’2d ago
No worries - if you're planning on sharing this API between multiple platforms, I highly recommend checking out https://trpc.io/ - it's significantly easier to package and share, handles most of the fetching headaches for you and allows you to communicate with your backend via React Query APIs. https://create.t3.gg/ as a starter kit has a really great starter setup and example of how to use tRPC πŸ™‚
tRPC - Move Fast and Break Nothing. End-to-end typesafe APIs made e...
End-to-end typesafe APIs made easy. Automatic typesafety & autocompletion inferred from your API-paths, their input data, & outputs πŸ§™β€β™‚οΈ
Create T3 App
Create T3 App
The best way to start a full-stack, typesafe Next.js app.
Yoshify
Yoshifyβ€’2d ago
In the case that you want to stick with traditional NextJS API route handlers though, instead of doing your fetch in a server action do it through a client component. I recommend using React Query at the very least for handling this as you'll get caching, loading states, etc.
moggelitalanya
moggelitalanyaOPβ€’2d ago
Ive ran with the nextjs API as ive learned that its very simple to setup and hosted within your domain (automatically), this might be the case with tRPC aswell? Thank you again, i will surely get further with this information. If not, i will return , hehe. Have a good night!
Yoshify
Yoshifyβ€’2d ago
tRPC is a library that integrates with almost any framework and allows you to choose how to expose it - for example, in NextJS, you could have it exposed on your domains /api endpoint just like a traditional route handler. All this is at the end of the day is a much nicer wrapper around it πŸ™‚ the example from Create T3 App shows you how to do this. No worries! Let me know if you have any dramas.
Want results from more Discord servers?
Add your server