clerk / javascript

Official Javascript repository for Clerk authentication
https://clerk.com
MIT License
1.05k stars 238 forks source link

Error: Invalid JWT form. A JWT consists of three parts separated by dots #1077

Closed kachar closed 1 year ago

kachar commented 1 year ago

Middleware works locally but when we deploy on Vercel the session cannot be parsed

Error: Invalid JWT form. A JWT consists of three parts separated by dots.
    at (node_modules/@clerk/backend/dist/esm/index.js:64:4787)
    at (node_modules/@clerk/backend/dist/esm/index.js:64:11143)
    at (node_modules/@clerk/backend/dist/esm/index.js:64:13218)
    at (node_modules/@clerk/backend/dist/esm/index.js:64:12937)
    at (node_modules/@clerk/backend/dist/esm/index.js:64:13099)
    at (node_modules/@clerk/backend/dist/esm/index.js:64:14093)
    at (node_modules/@clerk/nextjs/dist/server/withClerkMiddleware.js:37:0)
    at (node_modules/next/dist/esm/server/web/adapter.js:103:0) {
  reason: 'token-invalid',
  action: undefined
}

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_cHVtcGVkLW1hZ2dvdC0yOS5jbGVyay5hY2NvdW50cy5kZXYk

Package + Version

Dependencies + versions

Provide a json with the dependencies used in your project (copy paste from yarn.lock / package-lock.json) or a github project / template that reproduces the issue.

*Include the @clerk/ packages and their versions!**

Example:

{  
  "dependencies": {
    "@clerk/nextjs": "^4.16.2",
    "@clerk/themes": "^1.6.1",
    "@dqbd/tiktoken": "^1.0.6",
    "@tabler/icons-react": "^2.16.0",
    "@tanstack/react-query": "^4.29.3",
    "@trpc/client": "^10.20.0",
    "@trpc/next": "^10.20.0",
    "@trpc/react-query": "^10.20.0",
    "@trpc/server": "^10.20.0",
    "@yarnpkg/pnpify": "^4.0.0-rc.42",
    "bson": "^5.2.0",
    "clsx": "^1.2.1",
    "eventsource-parser": "^0.1.0",
    "i18next": "^22.4.14",
    "lodash": "^4.17.21",
    "mongodb": "^5.2.0",
    "next": "13.3.0",
    "next-i18next": "^13.2.2",
    "openai": "^3.2.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-gtm-module": "^2.0.11",
    "react-hot-toast": "^2.4.0",
    "react-i18next": "^12.2.0",
    "react-markdown": "^8.0.7",
    "react-syntax-highlighter": "^15.5.0",
    "remark-gfm": "^3.0.1",
    "superjson": "1.12.2",
    "uuid": "^9.0.0",
    "zod": "^3.20.2"
  },
  "devDependencies": {
    "@mozilla/readability": "^0.4.4",
    "@tailwindcss/typography": "^0.5.9",
    "@types/jsdom": "^21.1.1",
    "@types/lodash": "^4.14.194",
    "@types/node": "18.15.0",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "@types/react-gtm-module": "^2.0.1",
    "@types/react-syntax-highlighter": "^15.5.6",
    "@types/uuid": "^9.0.1",
    "@vitest/coverage-c8": "^0.29.7",
    "autoprefixer": "^10.4.14",
    "endent": "^2.1.0",
    "eslint": "8.36.0",
    "eslint-config-next": "13.2.4",
    "gpt-3-encoder": "^1.1.4",
    "jsdom": "^21.1.1",
    "postcss": "^8.4.21",
    "prettier": "^2.8.7",
    "prettier-plugin-tailwindcss": "^0.2.5",
    "tailwindcss": "^3.2.7",
    "tslib": "^2.5.0",
    "typescript": "4.9.5",
    "vitest": "^0.29.7"
  }
}

Browser/OS

Any

Description

We're using Clerk with tRPC in a similar way as it's defined in the starter https://github.com/clerkinc/t3-turbo-and-clerk

The middleware.ts is as follows:

import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { routes } from './routes'

// Set the paths that don't require the user to be signed in
const publicPaths = [`/sign-in*`, `/sign-up*`]

const isPublic = (path: string) => {
  return publicPaths.find((x) => path.match(new RegExp(`^${x}$`.replace('*$', '($|/)'))))
}

export default withClerkMiddleware((request: NextRequest) => {
  if (isPublic(request.nextUrl.pathname)) {
    return NextResponse.next()
  }
  // if the user is not signed in redirect them to the sign in page.
  const { userId } = getAuth(request)
  if (!userId) {
    // redirect the users to /pages/sign-in/[[...index]].ts

    const signInUrl = new URL(routes.signIn, request.url)
    signInUrl.searchParams.set('redirect_url', request.url)
    return NextResponse.redirect(signInUrl)
  }
  return NextResponse.next()
})

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next
     * - static (static files)
     * - favicon.ico (favicon file)
     * - public folder
     */
    '/(.*?trpc.*?|(?!static|.*\\..*|_next|favicon.ico|site.manifest).*)',
    '/',
  ],
}

The root / is not public, and we check the user authentication in order to provide proper redirects

The result is that the user ends up on /sign-in page even when they are authenticated.

I've manually checked every JWT in localStorage and cookies and they are all with valid signatures - __session, clerk-db-jwt, __dev_session

_clerk_js_version: 4.37.0

kachar commented 1 year ago

The issue was resolved by re-applying the environment variables in Vercel, seems when the secret key contains whitespace or is wrong Invalid JWT form error is thrown.