#logs are not very description for an auth issue: 'Invalid verifier' - Issue is nextjs middleware.ts

20 messages · Page 1 of 1 (latest)

scarlet stag
#

logs are not very description for an auth issue: 'Invalid verifier' - Issue is middleware.ts

#

I thought i'd create a thread for this originally I was just getting these errors

9/1/2025, 5:08:19 PM [CONVEX M(auth:store)] [INFO] '`auth:store` type: verifier'
9/1/2025, 5:08:19 PM [CONVEX M(auth:store)] [INFO] '`auth:store` type: verifierSignature'
9/1/2025, 5:08:39 PM [CONVEX M(auth:store)] [INFO] '`auth:store` type: userOAuth'
9/1/2025, 5:08:39 PM [CONVEX M(auth:store)] [INFO] '`auth:store` type: verifyCodeAndSignIn'
9/1/2025, 5:08:39 PM [CONVEX M(auth:store)] [ERROR] 'Invalid verifier'

wasn't sure why I started getting these and had to backtrack a bit to find out why.

#

The "invalid verifier" didn't really help me find out why, turns out having a middleware.ts, copied exactly from https://labs.convex.dev/auth/authz/nextjs, or not having the middleware.ts is the differentiator between working auth and not working auth that throws the error above.

#

import {
    convexAuthNextjsMiddleware,
    createRouteMatcher,
    nextjsMiddlewareRedirect,
  } from "@convex-dev/auth/nextjs/server";
   
  const isSignInPage = createRouteMatcher(["/sign-in"]);
  const isProtectedRoute = createRouteMatcher(["/dashboard(.*)"]);
   
  export default convexAuthNextjsMiddleware(async (request, { convexAuth }) => {
    if (isSignInPage(request) && (await convexAuth.isAuthenticated())) {
      return nextjsMiddlewareRedirect(request, "/product");
    }
    if (isProtectedRoute(request) && !(await convexAuth.isAuthenticated())) {
      return nextjsMiddlewareRedirect(request, "/sign-in");
    }
  });
   
  export const config = {
    // The following matcher runs middleware on all routes
    // except static assets.
    matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
  };
#

logs are not very description for an auth issue: 'Invalid verifier' - Issue is nextjs middleware.ts

scarlet stag
#

Originally my middleware had custom logic for redirecting users around as I needed, but I copied it exactly to whats in the docs to remove extra variables

floral mountain
#

Are you saying that this middleware caused the error, or removing it caused the error? Trying to understand actual vs expected

scarlet stag
#

having the middleware causes the issue to happen @floral mountain

#

not having it allows me to log in correctly

#

More details include:

I am using discord oauth, I havent tried other login methods

as a work around I am using a client-side "middleware" to navigate me around based on auth state. It's janky but works for now.

floral mountain
#

Can you share your ConvexClientProvider.tsx and your root layout

scarlet stag
#
"use client";

import { ReactNode } from "react";
import { ConvexReactClient } from "convex/react";
import { ConvexAuthProvider } from "@convex-dev/auth/react";

const convexUrl =
    process.env.NEXT_PUBLIC_CONVEX_URL;
if (!convexUrl) {
    throw new Error(
        "Convex URL missing. Set NEXT_PUBLIC_CONVEX_URL.",
    );
}
const convex = new ConvexReactClient(convexUrl);

export default function ConvexClientProvider({
    children,
}: {
    children: ReactNode;
}) {
    return <ConvexAuthProvider client={convex}>{children}</ConvexAuthProvider>;
}
#
import "./globals.css";
import type { Metadata } from "next";
import { Geist_Mono, Plus_Jakarta_Sans, Baloo_2 } from "next/font/google";
import ConvexClientProvider from "../../../../components/ConvexClientProvider";
import { Background } from "../components/Background";
import TopNav from "../components/TopNav";

const plusJakarta = Plus_Jakarta_Sans({
    variable: "--font-geist-sans",
    subsets: ["latin"],
    display: "swap",
    fallback: [
        "Zen Kaku Gothic New",
        "Hiragino Kaku Gothic ProN",
        "Yu Gothic",
        "Meiryo",
        "system-ui",
        "sans-serif",
    ],
});

const baloo = Baloo_2({
    variable: "--font-display",
    subsets: ["latin"],
    weight: "500",
    display: "swap",
});

const geistMono = Geist_Mono({
    variable: "--font-geist-mono",
    subsets: ["latin"],
});

export const metadata: Metadata = {
    title: "Create Next App",
    description: "Generated by create next app",
};

export default async function RootLayout({
    children,
}: Readonly<{
    children: React.ReactNode;
}>) {
    return (
        <html lang="en">
            <head>
                <link
                    rel="stylesheet"
                    href="https://cdn.jsdelivr.net/gh/lipis/[email protected]/css/flag-icons.min.css"
                />
            </head>
            <body
                suppressHydrationWarning
                className={`${plusJakarta.variable} ${geistMono.variable} ${baloo.variable} antialiased`}
            >
                <ConvexClientProvider>
                    <div className="min-h-screen px-4 max-w-7xl mx-auto">
                        <Background />
                        <TopNav />
                        {children}
                    </div>
                </ConvexClientProvider>
            </body>
        </html>
    );
}

floral mountain
#

Did these change since you were hitting those errors or is this how they've been

scarlet stag
#

the only change was that ConvexCleintProvider used to have a ?? for the EXPO_PUBLIC_CONVEX_URL

#
"use client";

import { ReactNode } from "react";
import { ConvexReactClient } from "convex/react";
import { ConvexAuthProvider } from "@convex-dev/auth/react";

const convexUrl =
    process.env.NEXT_PUBLIC_CONVEX_URL ?? process.env.EXPO_PUBLIC_CONVEX_URL;
if (!convexUrl) {
    throw new Error(
        "Convex URL missing. Set NEXT_PUBLIC_CONVEX_URL (web) or EXPO_PUBLIC_CONVEX_URL (mobile).",
    );
}
const convex = new ConvexReactClient(convexUrl);

export default function ConvexClientProvider({
    children,
}: {
    children: ReactNode;
}) {
    return <ConvexAuthProvider client={convex}>{children}</ConvexAuthProvider>;
}

heres the old version

#

its likely unrelated, but it is the only change.

floral mountain
#

You're only using the react client, so your setup won't be compatible with middleware or anything that requires server side auth.

If you want to use middleware and SSA in general, you'll want to follow the steps for that in the docs.

Go here: https://labs.convex.dev/auth/setup#set-up-the-react-provider

Make sure to select "Next.js" and "App Router with SSA".

scarlet stag
#

Ah that was easy

#

thanks