Search code examples
next.jsfetch-apiclerk

Clerk back end API always gives status code of 401


I'm trying to fetch a specific user with the Clerk backend API. Here's the endpoint: https://api.clerk.com/v1/users/{user_id}. I'm using the Nextjs fetch function to get the data:

try {
            const userProfileData = await fetch(
                `https://api.clerk.com/v1/users/${user}`,
                {
                    method: "GET",
                    mode: "no-cors",
                    headers: {
                        "Content-Type": "application/json",
                    },
                }
            );
            console.log(userProfileData);
        } catch (error) {
            console.error(error);
        }
    

This code returns status code 401 with a response for Clerk:

Response {type: 'opaque', url: '', redirected: false, status: 0, ok: false, …}
body
: 
(...)
bodyUsed
: 
false
headers
: 
Headers
[[Prototype]]
: 
Headers
ok
: 
false
redirected
: 
false
status
: 
0
statusText
: 
""
type
: 
"opaque"
url
: 
""
[[Prototype]]
: 
Response

It also produces two Nextjs errors:

Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.

See more info here: https://nextjs.org/docs/messages/react-hydration-error
Unhandled Runtime Error
Error: There was an error while hydrating this Suspense boundary. Switched to client rendering.

I've also tried wrapping the code with useEffect to no avail. Other Clerk APIs return similar responses.


Solution

  • It sounds like you need to configure the middleware to recognize your routes. Doc for Clerk with Next.js:

    📍 https://clerk.com/docs/references/nextjs/auth-middleware

    With the proper config, your app will know which routes are for the API and not 401 those.

    Please start with this guide, and begin with the most simple implementation of authMiddleware. Rule of thumb: keep it simple (only use options if necessary) and stick to the doc-examples.

    You probably won't need the next-intl and beforeAuth bits, but you can think about those for later.

    Focus on the afterAuth implementation, be sure to set your apiRoutes and publicRoutes options, and possibly ignoredRoutes option if necessary. Get it working in basic form and then add a feature at a time so know if and what breaks.

    Here's the final/compiled example from the Clerk docs - which you may work yourself up to by the end, and which also may need some adjustments for your app.

    /src/middleware.ts:

    import { authMiddleware, redirectToSignIn } from '@clerk/nextjs';
     
    export default authMiddleware({
      apiRoutes: ['/(api|trpc)(.*)'], // Per `matcher` - `publicRoutes` override this
      publicRoutes: ['/sign-in', '/sign-up'],
      afterAuth(auth, req, evt) {
        // Allow matched api/public requests
        if (auth.isApiRoute || auth.isPublicRoute) {
          return response
        }
        // handle users who aren't authenticated
        if (!auth.userId && !auth.isPublicRoute) {
          return redirectToSignIn({ returnBackUrl: req.url });
        }
        // Ex. // redirect them to organization selection page
        // if (auth.userId && !auth.orgId && req.nextUrl.pathname !== "/org-selection"){
        //   const orgSelection = new URL('/org-selection', req.url)
        //   return NextResponse.redirect(orgSelection)
        // }
      }
    });
    
    
    export const config = {
      matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
    };