Open steve-marmalade opened 5 days ago
Hey @steve-marmalade,
Thanks for reporting!
In 1.8 I overhauled how credentials are parsed and serialized into cookies, which might've introduced this issue.
Do I understand that you get this error in handleError
callback?
Could you provide more details, ideally a stack trace?
Hi @awinogrodzki, I just started using v1.8.0
and similarly I'm also seeing this error in my logs whenever the authMiddleware
is run. Here is the stack trace on my end:
at (node_modules/.pnpm/next-firebase-auth-edge@1.8.0_next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/next-firebase-auth-edge/browser/next/cookies/parser/SingleCookieParser.js:13:0)
at (node_modules/.pnpm/next-firebase-auth-edge@1.8.0_next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/next-firebase-auth-edge/browser/next/tokens.js:18:0)
at (node_modules/.pnpm/next-firebase-auth-edge@1.8.0_next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1_/node_modules/next-firebase-auth-edge/browser/next/middleware.js:107:29)
at (middleware.ts:14:9)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/esm/server/web/adapter.js:175:17)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/esm/server/async-storage/request-async-storage-wrapper.js:95:0)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/esm/server/web/adapter.js:166:45)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/esm/server/lib/trace/tracer.js:114:0)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:7052)
at (node_modules/.pnpm/next@14.2.9_@babel+core@7.25.2_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:480)
Hey @teresal92 !
Thanks for chiming in! Could you share your middleware.ts
file?
I am interested in what's on line 14: at (middleware.ts:14:9)
I am also getting the same error, after having following the docs.
Here is my middleware.ts:
import type { NextRequest } from "next/server";
import { authMiddleware } from "next-firebase-auth-edge";
export async function middleware(request: NextRequest) {
console.log(process.env.NEXT_PUBLIC_FIREBASE_API_KEY)
return authMiddleware(request, {
debug: true,
loginPath: "/api/login",
logoutPath: "/api/logout",
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
cookieName: "AuthToken",
cookieSignatureKeys: ["Key-Should-Be-at-least-32-bytes-in-length"],
cookieSerializeOptions: {
path: "/",
httpOnly: true,
secure: false, // Set this to true on HTTPS environments
sameSite: "lax" as const,
maxAge: 12 * 60 * 60 * 24, // Twelve days
},
serviceAccount: {
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
clientEmail: process.env.NEXT_PUBLIC_FIREBASE_CLIENT_EMAIL,
privateKey: process.env.NEXT_FIREBASE_PRIVATE_KEY,
},
});
}
export const config = {
matcher: ["/api/login", "/api/logout", "/", "/((?!_next|favicon.ico|api|.*\\.).*)"],
};
Thank you @goncaloalves! Would you be able to share the stack trace as well? I just want to rule out different sources for the issue
i just have this:
ⓘ next-firebase-auth-edge: Handle request
path: /signin
ⓘ next-firebase-auth-edge: Token is missing or has incorrect formatting. This is expected and usually means that user has not yet logged in
message: MISSING_CREDENTIALS: Missing credentials
reason: MISSING_CREDENTIALS
stack: Error: MISSING_CREDENTIALS: Missing credentials
at SingleCookieParser.parseCookies (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/browser/next/cookies/parser/SingleCookieParser.js:20:19)
at getRequestCookiesTokens (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/browser/next/tokens.js:37:19)
at authMiddleware (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/browser/next/middleware.js:126:97)
at Object.middleware [as handler] (webpack-internal:///(middleware)/./middleware.ts:10:83)
at eval (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/web/adapter.js:197:31)
at AsyncLocalStorage.run (node:async_hooks:346:14)
at Object.wrap (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/async-storage/request-async-storage-wrapper.js:105:24)
at eval (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/web/adapter.js:188:122)
at eval (webpack-internal:///(middleware)/./node_modules/next/dist/esm/server/lib/trace/tracer.js:115:36)
at NoopContextManager.with (webpack-internal:///(middleware)/./node_modules/@opentelemetry/api/build/esm/context/NoopContextManager.js:58:24)
@goncaloalves does the issue still log when you change to debug: false,
in authMiddleware
?
yes, I placed debug true to try and debug it myself.
Hey @awinogrodzki, here's my middleware.ts
:
line 14
is returning authMiddleware
import {
authMiddleware,
redirectToPath,
redirectToLogin,
} from 'next-firebase-auth-edge'
import { serverConfig, clientConfig } from './lib/firebase/config'
const PUBLIC_PATHS = ['/signup', '/login', '/forgot-password', '/']
const PROTECTED_PATHS = ['/home', '/home/onboarding']
export async function middleware(request: NextRequest) {
// https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-minimal/middleware.ts
return authMiddleware(request, {
loginPath: '/api/login',
logoutPath: '/api/logout',
apiKey: clientConfig.apiKey,
cookieName: serverConfig.cookieName,
cookieSignatureKeys: serverConfig.cookieSignatureKeys,
cookieSerializeOptions: serverConfig.cookieSerializeOptions,
serviceAccount: serverConfig.serviceAccount,
handleValidToken: async ({ token }, headers) => {
// Authenticated user should not be able to access /login, /signup and /forgot-password routes
if (PUBLIC_PATHS.includes(request.nextUrl.pathname) && token) {
return redirectToPath(request, '/home')
}
return NextResponse.next({
request: {
headers,
},
})
},
handleInvalidToken: async (reason) => {
if (PROTECTED_PATHS.includes(request.nextUrl.pathname)) {
console.info('Missing or malformed credentials', { reason })
// redirect to /login if the user is not authenticated
return redirectToLogin(request, {
path: '/login',
publicPaths: PUBLIC_PATHS,
})
}
return NextResponse.next()
},
handleError: async (error) => {
console.error('Unhandled authentication error', { error })
return redirectToLogin(request, {
path: '/login',
publicPaths: PUBLIC_PATHS,
})
},
})
}
export const config = {
matcher: [
'/api/login',
'/api/logout',
'/((?!api|_next/static|_next/image|.*\\.).*)',
],
}
Thank you @teresal92!
That's interesting, I am not able to reproduce the issue myself – @teresal92, do you have the rest of the stack trace? Does it log out as Unhandled authentication error
or Missing or malformed credentials
?
Ultimately, I am most interested if the error is logged in handleInvalidToken
or handleError
method.
console.info('Missing or malformed credentials', { reason })
is purely informative and can be safely removed. handleInvalidToken
is expected to be called.
If the error is logged out insidehandleError
, then it's something that I need to pin-point and fix
There is also a third case where the error is unhandled by neither handleInvalidToken
nor handleError
, which would also be identifiable by the rest of the stack trace
@goncaloalves could you share the logs of the error with debug: false
? I want to understand if the error is somehow recoverable. If yes, what is the source of it
I'm seeing the same issue, btw - it started with the 1.8 update.
Error: MISSING_CREDENTIALS: Missing credentials at (../../node_modules/next-firebase-auth-edge/browser/next/cookies/parser/SingleCookieParser.js:13:0)
Everything works fine in localhost, but I get the error on my Vercel staging site.
Hey @michael5r,
Does the app stop from working after this error, or is it recoverable?
Could you share the rest of the stack-trace? SingleCookieParser
can be used in multiple places. I need to understand whether the issue originates from getTokens
, authMiddleware
or one of the error handling functions
I think I was finally able to reproduce the issue on Vercel – thanks everyone for cooperation – I will start working on a fix shortly
It seems that authMiddleware
error is not catched by neither handleInvalidError
nor handleError
. The following condition returns false
on some Edge Middleware executions:
error instanceof InvalidTokenError
It's not consistent. Most of the time the check works as expected. I think it has something to do with a changes I did around ESM, Browser and Node modules. One reason for it might be that Vercel is using different type of InvalidTokenError
constructor between throwing an error and checking it's instance using instanceof
operator.
I've added some additional logs in latest canary release and will provide further updates soon
I think I know what's happening. Looks like Vercel is trying to guess and log errors that resulted from unhandled promises. It may involve a Proxy over Promise
and Error
classes.
The app handles the error correctly, but despite that it is picked up by Vercel and logged as error. It can be somehow related to the v1.8 though
@steve-marmalade, @teresal92, @goncaloalves, @michael5r can I ask you to confirm that you all see the error in Vercel, but not locally (with debug: false)? Most likely it's a false positive due to some change on how Vercel reports Errors.
I will research further if we could mark this as error as handled in Vercel
@awinogrodzki Yep, it doesn't happen locally - only on Vercel.
I have found a potential fix for the issue.
It's related to the problem mentioned in the previous comment. The details can be found in PR description
Could you install next-firebase-auth-edge@1.8.2-canary.10
and let me know if it works for you?
Hello! I am seeing lots of log lines like the following:
I believe this came after updating to 1.8 but not 100% sure.
Can you provide some more background on this? For reference, it's expected that a lot of our traffic is logged-out so I don't think of missing credentials as an error state. So is this something I should ignore (and if so, is there a way to silence this message?) or is it indicating some kind of configuration error on my part?
Thank you.