oscklm
oscklm11mo ago

Is it possible to call convex from within a middleware.ts

I'm playing around with the new clerkMiddleware and trying to see if there would be a way for me to check if a user has a certain role by calling convex and index the users table with the token and check if that user has the role we want?
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

const isHubRoute = createRouteMatcher(["/hub(.*)"]);

const isAdminRoute = createRouteMatcher(["/admin(.*)"]);

export default clerkMiddleware(
(auth, req) => {
// Restrict admin routes to users with administrative permissions
if (isAdminRoute(req)) {
auth().protect((has) => {
const token = auth().getToken();

// Call convex with the token and check for admin role
// ...
const isAdmin = checkAdminRole(token);

return isAdmin; // Adjust permission identifier as needed
});
} else if (isHubRoute(req)) {
auth().protect();
}
},
{ debug: true }
);

// Config matcher might still be used to apply this middleware correctly based on your app's routing
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

const isHubRoute = createRouteMatcher(["/hub(.*)"]);

const isAdminRoute = createRouteMatcher(["/admin(.*)"]);

export default clerkMiddleware(
(auth, req) => {
// Restrict admin routes to users with administrative permissions
if (isAdminRoute(req)) {
auth().protect((has) => {
const token = auth().getToken();

// Call convex with the token and check for admin role
// ...
const isAdmin = checkAdminRole(token);

return isAdmin; // Adjust permission identifier as needed
});
} else if (isHubRoute(req)) {
auth().protect();
}
},
{ debug: true }
);

// Config matcher might still be used to apply this middleware correctly based on your app's routing
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
7 Replies
ian
ian11mo ago
Yes you could use the ConvexHTTPClient or the react client's async client.query function to call a Convex query from outside of a React context. Try to make it a single query that does it all, instead of many queries, since the Next.js server has a variavble network distance from the Convex server. Especially if you're running any of this from the edge
oscklm
oscklmOP11mo ago
Thanks. I was thinking of using the ConvexHTTPClient, which would make sense, and give me some more type safety i would assume right? I went with a simple fetch post request as i played around with it. Would love some feedback on this - unsure if there are any potential issues from a convex pov, or some over complication in my approach. I'm even thinking of potentially handling the initial storing of the user in this middleware. Not sure if the many calls to convex on each navigation would be smart... not a big issue though
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";

const isHubRoute = createRouteMatcher(["/hub(.*)"]);
const isAdminRoute = createRouteMatcher(["/admin(.*)"]);

export default clerkMiddleware(async (auth, req) => {
try {
// Handle navigation to auth route
if (isAdminRoute(req)) {
// Get the token from Clerk
const token = await auth().getToken({ template: "convex" });

// Verify the role of the user
const response = await fetch(
`${process.env.NEXT_PUBLIC_CONVEX_SITE}/checkRole`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ role: "admin" }),
}
);

const data = await response.json();
const { isAuthorized } = data;

// Unauthorized navigation to admin route, rewrite to not-found to not expose admin route
if (!isAuthorized) {
return NextResponse.rewrite(new URL("/not-found", req.url));
}

// Handle authorized navigation to admin route
auth().protect();
}

// Handle navigation to hub route
if (isHubRoute(req)) {
auth().protect();
}
} catch (error) {
console.error("Error in middleware authentication:", error);
auth().protect();
}
});

export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";

const isHubRoute = createRouteMatcher(["/hub(.*)"]);
const isAdminRoute = createRouteMatcher(["/admin(.*)"]);

export default clerkMiddleware(async (auth, req) => {
try {
// Handle navigation to auth route
if (isAdminRoute(req)) {
// Get the token from Clerk
const token = await auth().getToken({ template: "convex" });

// Verify the role of the user
const response = await fetch(
`${process.env.NEXT_PUBLIC_CONVEX_SITE}/checkRole`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ role: "admin" }),
}
);

const data = await response.json();
const { isAuthorized } = data;

// Unauthorized navigation to admin route, rewrite to not-found to not expose admin route
if (!isAuthorized) {
return NextResponse.rewrite(new URL("/not-found", req.url));
}

// Handle authorized navigation to admin route
auth().protect();
}

// Handle navigation to hub route
if (isHubRoute(req)) {
auth().protect();
}
} catch (error) {
console.error("Error in middleware authentication:", error);
auth().protect();
}
});

export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
One thing i'm wishing to implement is some rate limiting, looking into that.
oscklm
oscklmOP11mo ago
Stumbled over this article, so kinda makes me rethink if middleware.ts is a bad place to handle this?https://pilcrow.vercel.app/blog/clerk-nextjs-vulnerability Would love to hear @Michal Srb take on this, sorry for tagging you directly. But if im not mistaken you've played around quite a bit with auth with convex, both with clerk and such?
Pilcrow
Investigating a major security vulnerability with Clerk's Next.js i...
Figuring out how a major auth provider fucked up.
oscklm
oscklmOP11mo ago
Key Takeaway from the Investigating a major security vulnerability with Clerk's Next.js i...: The article uncovers a critical security vulnerability (CVSS 9.4) in the Clerk's Next.js integration that could allow malicious actors to impersonate users by exploiting how authentication tokens and statuses are handled between middleware and route handlers. The vulnerability highlights the dangers of relying on middleware for authentication in frameworks like Next.js, which separates middleware and route handlers, potentially allowing exploitation through misaligned token checks. How this Relates to Your Code: The vulnerability discussed could directly impact the way you handle auth in your middleware.ts, particularly if similar patterns or methods are used. It's crucial to ensure your authentication checks are aligned correctly between middleware and endpoint handlers and verify tokens are validated securely to prevent impersonation or unauthorized access. Generated by ChatGPT
Michal Srb
Michal Srb11mo ago
Next.js Server Rendering | Convex Developer Hub
Next.js automatically renders both Client and Server Components on the server
oscklm
oscklmOP11mo ago
Ohh cool, i was not aware of that! thanks

Did you find this page helpful?