How do you use Clerk with tRPC successfully?
We've been using Clerk with tRPC and Remix. So our application makes requests to tRPC in the usual way, and I try get get auth like this:
import { getAuth } from "@clerk/remix/ssr.server.js";
import { FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch";
import { getUserIdFromAuth } from "app/integrations/clerk.server";
export async function createContext({
req,
resHeaders,
}: FetchCreateContextFnOptions) {
const headers = Object.fromEntries(req.headers.entries());
const auth = await getAuth({
request: req,
context: {},
params: {},
});
let userId: string | null = null;
if (auth.userId) {
userId = (await getUserIdFromAuth(auth)) || null;
}
return { req, resHeaders, userId };
}
This works at first but is not actually good at all: the getAuth method in Clerk makes a pretty hard assumption that it can throw an error and present an interstitial page. Which in a tRPC context makes no sense - you're doing an API request, and getting back a HTML page instead of JSON isn't going to work.
So, we get crashes in prod and pretty polluted logs. What's the right way to do this? As it is, I don't see how to make Clerk work with tRPC, to get a user's auth from an API request and not break the API endpoint.
@tmcw Geniune question as I'm interested in using trpc + clerk for an astro app and I imagine my use would have this same problem:
Why aren't we treating this as a fail-able effect like any other fail-able effect?
- We're reaching into a space where the total type of the function always includes a failure. How is this any different from a timed-out database request?
Given that this is an issue that's been given priority by the company, I trust that this is a legitimate concern. I'm just trying to understand how this is such a show-stopper.
My understanding so far is that basically Clerk refreshes tokens very often, and it does so - when I'm using Remix - by having a custom loader, returning an interstitial response, which triggers a token refresh. This has problems of its own, but - when I'm using tRPC as well, when a request fails, right now it triggers an interstitial - the tRPC endpoint returns HTML instead of JSON and breaks the site. I could treat that as failable, but that leaves open the question of how the token will get refreshed.
We haven't really found a reliable pattern for using Clerk with tRPC or API routes in general, and I haven't seen one suggested (at least for Remix) anywhere. So like you could let your API routes 400, but they'll continue to 400 and you won't get a token refresh like you should.
I'm also having this issue. Using Next.js + tRPC + clerk
I'm not sure that the prioritized label is much reason for hope, my other issue has been stalled for ~~seven months~~ almost ~nine~ ~~ten months~~ going on a year but it's prioritized.
Hello @tmcw, @octoper is looking into the Remix + tRPC integration this week, so we'll be able to share more details soon. We'll be looking into the Nextjs issue right after.
Regarding #1043, I will need to check with the team before I can share details - apologies for that.
Hello @tmcw I took a look at it, and indeed the getAuth inside the tRPC context throws an error when the interstitial criteria are met, but it doesn't actually return an HTML at that point, instead it's just returns an object so we know that an interstitial page has to be thrown, there you could wrap the getAuth in a try/catch block and handle any errors thrown as the user was not authenticated to avoid all those polluted logs you mentioned, now for the part of how the token will be refresh is up to the rootAuthLoader to handle if an interstitial page has to be thrown.
You can also take a look at a simple example I made on how to use Clerk, tRPC and Remix, you can check it here.
Hello @kmkinney, I have not checked out yet with Next.js but we have a starter (https://github.com/clerkinc/t3-turbo-and-clerk) that you can take a look in case something is not configured properly in your app.
Hello! 👋 Please let me know if the suggested solution worked for you or if you have any questions. Your feedback is important to us. If there is no response within 7 days, we will consider the issue resolved and close it. Feel free to reopen it or reach out for further assistance. Thanks! 🚀
@octoper this is absoltely not resolved – next app router + trpc + clerk is broken
i agree this is not resolved at all, integrating clerk into a next 14 app with the app dir and using trpc throws cryptic errors regularly. right now im getting something in the likes of "cannot reading property of undefined (reading resolve)" . given that there is not description other than "add public routes to middleware.ts its not exactly clear what the issue is or if this is even on the lib side of things. please advise on the trpc + clerk docs :)
On our deployed netlify site, we always get getAuth() error when refreshing a page that uses a mutation or query. Those queries only work if you first navigate to another page and then to the page that uses that TRPC functionality, pretty broken:
"trpcState": {
"json": {
"mutations": [
],
"queries": [
{
"state": {
"data": null,
"dataUpdateCount": 0,
"dataUpdatedAt": 0,
"error": {
"message": "Clerk: getAuth() was called but Clerk can't detect usage of authMiddleware(). Please ensure the following:\n- authMiddleware() is used in your Next.js Middleware.\n- Your Middleware matcher is configured to match this route or page.\n- If you are using the src directory, make sure the Middleware file is inside of it.\n\nFor more details, see https://clerk.com/docs/quickstarts/get-started-with-nextjs.\n",
"data": {
"code": "INTERNAL_SERVER_ERROR",
"httpStatus": 500
.....
Second this, clerk + app router + trpc is completely broken
The page doesn't load and just keeps refreshing. Also getting random 401 errors even though trpc routes are set to public
I'm about to setup next 14 + clerk + trpc and came across this issue. From what I can tell, there is a working example here for how to setup the TRPC context here: https://github.com/clerk/t3-turbo-and-clerk/blob/main/packages/api/src/context.ts
It seems important to distinguish between the import { auth } from "@clerk/nextjs"; and import { getAuth } from "@clerk/nextjs/server"; as the former does all all sorts of next redirects and such and the latter looks at the headers that should have been already set by the middleware. This also means that it is important to run the clerk middleware on the TRPC endpoint url.
See this file for more: https://github.com/clerk/javascript/blob/main/packages/nextjs/src/server/getAuth.ts
Is there any working example of how we can intergate it similair to this example:
https://github.com/clerk/t3-turbo-and-clerk/blob/main/packages/api/src/context.ts
but using the Next JS App Router and publicRoutes in middleware.ts?
the publicRoutes option was not working for me, and I could not remove the /api/trpc matcher from the nextjs middleware matcher option.
So I just used the ignoredRoutes options to make some of my trpc endpoints public. It's working for me so far.
import { authMiddleware } from "@clerk/nextjs";
export default authMiddleware({
publicRoutes: [
"/api/trpc/public.getOrgInfo(.*)",
"/",
"/api/status/change",
"/api/generatePresignedS3Url(.*)",
"/application(.*)",
"/api/agent",
"/api/conversation",
"/api/organization",
"/api/message/ai",
"/api/message/client",
"/api/release-conversations",
"/application/(.*)",
"/api/trpc/application(.*)",
"/api/trpc/public(.*)",
],
// ignore /api/trpc/public
ignoredRoutes: ["/api/trpc/public(.*)"],
});
export const config = {
matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};
Hi All, I got this working smoothly in my application. I created a gist with the basics of how to do it: https://gist.github.com/mkcode/a590d1c8f7b0a37b8299965de7f7e958
Hello and thank you all for your patience. The interstitial mechanism in previous versions was indeed causing issues like the ones you've described. To address this, we have completely replaced it in our latest Core 2 release with a new mechanism to mitigate such issues.
We advise updating to the latest major versions: either @clerk/remix@4 or @clerk/nextjs@5.
How to upgrade Remix to Core 2: https://clerk.com/docs/upgrade-guides/core-2/remix How to upgrade Nextjs to Core 2: https://clerk.com/docs/upgrade-guides/core-2/nextjs
What if one is using trpc but are not using remix or nextjs?