CodeWithAntonio
CodeWithAntonioβ€’12mo ago

Clerk Auth in Route Handlers

Hi everyone πŸ‘‹ I need help for a pretty specific edge case. A third party library which I use alongside Convex needs to generate an authentication token by using NextJS route handlers endpoint. Lets call this /api/third-party-auth In this route handler, which is a POST request, I need to have access to currently logged in user. I know I can access convex instance using the following: const convex = new ConvexHttpClient(process.env.NEXT_PUBLIC_CONVEX_URL!); But I am not sure if I can use that to access current auth. This is usualy accessible with @clerk/nextjs package, but as far as I understand, for Convex + Clerk we use @clerk/react package instead, and then we access "backend" auth using ctx.identity How would I solve this specific issue? Here are a couple of things that come to mind: - Add @clerk/nextjs & middleware.ts (I have a feeling this will break things) - convex/http (I tried this, but did not really understand if I can test this out locally?) - getToken I see this popping up in discord searches, but do not really understand how I should approach it. My main goal is to get access to user ID inside route handler (I also need user organization ID, but I will debug that later) Thanks!
15 Replies
Michal Srb
Michal Srbβ€’12mo ago
You can pass the Clerk JWT token to the POST next.js endpoint, then parse it there to get the client identity
Michal Srb
Michal Srbβ€’12mo ago
You'll need a way to validate the JWT token in the POST Request handler: https://clerk.com/docs/backend-requests/making/jwt-templates#using-a-template mentions using JWKS endpoint like https://clerk.your-site.com/.well-known/jwks.json And I think there are a bunch of libraries that can do this, one set here: https://jwt.io/libraries?language=JavaScript also https://www.npmjs.com/package/jsonwebtoken I have not done this myself, the built-in Convex auth integration is implemented in Rust, so I can't vouch for which library is best.
JWT.IO - JSON Web Tokens Libraries
Find an overview of libraries that help you work with JSON Web Tokens in your favorite language.
npm
jsonwebtoken
JSON Web Token implementation (symmetric and asymmetric). Latest version: 9.0.2, last published: 4 months ago. Start using jsonwebtoken in your project by running npm i jsonwebtoken. There are 26205 other projects in the npm registry using jsonwebtoken.
JWT templates | Clerk
Customize your authentication tokens and integrate with anyone.
Michal Srb
Michal Srbβ€’12mo ago
You indeed get the token via getToken from Clerk: https://clerk.com/docs/references/react/use-auth
useAuth() | Clerk
The useAuth() hook is a convenient way to access the current auth state. This hook provides the minimal information needed for data-loading and helper methods to manage the current active session.
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
Thank you for that info, I understand how I have to approach it now, the issue is the I don't exactly control the fetch method which the third-party library fires to my route handler endpoint πŸ˜… They do allow replacing the authEndpoint to be a callback instead, where I can have more options, but using hooks like useAuth is not one of them :/
import { createClient } from "@liveblocks/client";

const client = createClient({
authEndpoint: async (room) => {
const response = await fetch("/api/liveblocks-auth", {
method: "POST",
headers: {
Authentication: "<your own headers here>",
"Content-Type": "application/json",
},
body: JSON.stringify({ room }), // Don't forget to pass `room` down
});
return await response.json();
},
});
import { createClient } from "@liveblocks/client";

const client = createClient({
authEndpoint: async (room) => {
const response = await fetch("/api/liveblocks-auth", {
method: "POST",
headers: {
Authentication: "<your own headers here>",
"Content-Type": "application/json",
},
body: JSON.stringify({ room }), // Don't forget to pass `room` down
});
return await response.json();
},
});
I will contact them as well if they know a solution Maybe we can resolve this in another way too: Is it possible to use @clerk/nextjs and middleware.ts with Convex?
Michal Srb
Michal Srbβ€’12mo ago
Yeah so unfortunately looking at LiveBlocks they don't have their client setup done very well, so it might be hard to initialize the client in a component like this:
const clerk = useAuth();
const client = useMemo(() => createClient({
authEndpoint: async (room) => {
const token = clerk.getToken({template: "convex"});
const response = await fetch("/api/liveblocks-auth", {
method: "POST",
headers: {
Authentication: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ room }), // Don't forget to pass `room` down
});
return await response.json();
},
}), [clerk])
// presumably pass the client to a provider so that your app can use it
const clerk = useAuth();
const client = useMemo(() => createClient({
authEndpoint: async (room) => {
const token = clerk.getToken({template: "convex"});
const response = await fetch("/api/liveblocks-auth", {
method: "POST",
headers: {
Authentication: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ room }), // Don't forget to pass `room` down
});
return await response.json();
},
}), [clerk])
// presumably pass the client to a provider so that your app can use it
This should be possible, like their RoomProvider should take in the client, but at least from types it doesn't seem like they allow that. You can try calling createRoomContext in your root component and then providing everything it returns via your own provider... But it'll be messy for an example. You're in JS so different hacks are possible. You could grab the Clerk client and set it on a global that you access from the callback you pass to live blocks's createClient.
Michal Srb
Michal Srbβ€’12mo ago
It is possible to use server side clerk with Convex, but you'll have to pass the JWT from server side to client side, and deal with the JWT expiring (because the client will not be able to fetch a new one). I haven't done this yet with Clerk (and there are no examples for it afaik: https://discord.com/channels/856971667393609759/1192233628835520563), but it should be possible, we do this with Auth0 on the Convex dashboard.
Discord
Discord - A New Way to Chat with Friends & Communities
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
Thanks @Michal Srb! LiveBlocks team gave me this solution for now:
const { getToken } = useAuth();
const [ready, setReady] = useState(false);

useEffect(() => {
async function run() {
const token = await getToken({ template: "convex" });
sessionStorage.setItem("jwt", token!);
setReady(true);
}

run();
}, [getToken])
const { getToken } = useAuth();
const [ready, setReady] = useState(false);

useEffect(() => {
async function run() {
const token = await getToken({ template: "convex" });
sessionStorage.setItem("jwt", token!);
setReady(true);
}

run();
}, [getToken])
This way I can access it in their config file. Thanks for all the help!
Michal Srb
Michal Srbβ€’12mo ago
I've looked more into the Clerk setup, it has improved significantly since I last looked, and it provides seamless support for both client and server side. So to the original question, to access the user information in Next.js server component, server action, or route handler, you need: 1. Correct .env.local setup 2. Correct middleware.ts setup 3. Call auth() or currentUser() The setup is detailed here: https://clerk.com/docs/quickstarts/nextjs
Add authentication and user management to your Next.js app with Cle...
Learn how to use Clerk to quickly and easily add secure authentication and user management to your Next.js application. Clerk works seamlessly on both client side and server side components.
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
oooh I thought that we are required to use clerk/react only, and not allowed to use the nextjs clerk package? Nextjs package is how I usually use clerk in my tutorials. If I can do it using the nextjs package, that can simplify things a lot!
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
I am mostly interesetd in how step 8 would look like with using the other way ? https://docs.convex.dev/auth/clerk
Convex Clerk | Convex Developer Hub
Clerk is an authentication platform providing login via
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
(ConvexProviderWithClerk)
Michal Srb
Michal Srbβ€’12mo ago
It looks the same (only the import path changes to @clerk/nextjs). But beware of wrapping server components in ClerkProvider, it seems to lead to unexpected behaviors. Here’s an example repo using clerk and convex on both server and client: https://github.com/xixixao/saas-starter
GitHub
GitHub - xixixao/saas-starter: Convex, Clerk, Next.js, Convex Ents
Convex, Clerk, Next.js, Convex Ents. Contribute to xixixao/saas-starter development by creating an account on GitHub.
CodeWithAntonio
CodeWithAntonioOPβ€’12mo ago
ooooh thats great!!! thanks so much, will make my life easier haha I geniunely thought we had to do it using clerk/react only haha
Abhishek
Abhishekβ€’11mo ago
Could you tell me what kind of unexpected behaviors are caused ?
Michal Srb
Michal Srbβ€’11mo ago
GitHub
Wrapping redirect in ClerkProvider leads to spurious redirect Β·...
Preliminary Checks I have reviewed the documentation: https://clerk.com/docs I have searched for existing issues: https://github.com/clerk/javascript/issues I have not already reached out to Clerk ...

Did you find this page helpful?