Error: MISSING_CREDENTIALS: Missing credentials
steve-marmalade opened this issue · 33 comments
Hello! I am seeing lots of log lines like the following:
Error: MISSING_CREDENTIALS: Missing credentials
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.
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?
@awinogrodzki Fixed it for me. Thanks!
Awesome @laurensnl! Thanks for the update. I will prepare 1.8.2
release shortly 👍
Fixed it for me as well - thanks!
The fix was released in next-firebase-auth-edge@1.8.2
. Thanks all for helping with finding the issue! 🎉
Thanks for the deep-dive @awinogrodzki (esp since this seems like a false-positive error)! Confirmed that I am no longer seeing these log messages after upgrading to 1.8.2
Thanks @awinogrodzki so much! this fixed the issue for me as well. apologies for the delayed response.
Hi,
I am still getting this error. It works perfectly locally but once deployed to Firebase, I am getting the following error:
textPayload: "Missing or malformed credentials { reason: 'MISSING_CREDENTIALS' }"
Cheers
Olaf
Hey @nolafs,
Could you share the stack trace? If the missing credentials is logged with reason, probably you are logging it in "handleInvalidToken" method. In such case "missing credentials" is expected
This is my logs with debug turned on:
DEFAULT 2024-11-12T17:17:43.291599Z ⓘ next-firebase-auth-edge: Handle request
DEFAULT 2024-11-12T17:17:43.291721Z path: /login
DEFAULT 2024-11-12T17:17:43.291858Z ⓘ next-firebase-auth-edge: Attempt to fetch request cookies tokens
DEFAULT 2024-11-12T17:17:43.292150Z ⓘ next-firebase-auth-edge: Extracted jwt cookie
DEFAULT 2024-11-12T17:17:43.292161Z ⓘ next-firebase-auth-edge: Jwt cookie not found. Throwing InvalidTokenError.
DEFAULT 2024-11-12T17:17:43.292531Z ⓘ next-firebase-auth-edge: Token is missing or has incorrect formatting. This is expected and usually means that user has not yet logged in
DEFAULT 2024-11-12T17:17:43.292690Z message: MISSING_CREDENTIALS: Missing credentials
DEFAULT 2024-11-12T17:17:43.292699Z reason: MISSING_CREDENTIALS
DEFAULT 2024-11-12T17:17:43.292749Z stack: Error: MISSING_CREDENTIALS: Missing credentials at iq.parseCookies (/workspace/.next/server/src/middleware.js:15:55426) at i0 (/workspace/.next/server/src/middleware.js:15:60042) at no (/workspace/.next/server/src/middleware.js:15:64528) at nc (/workspace/.next/server/src/middleware.js:15:66531) at handler (/workspace/.next/server/src/middleware.js:15:67735) at AsyncLocalStorage.run (node:async_hooks:346:14) at /workspace/.next/server/src/middleware.js:13:32396 at AsyncLocalStorage.run (node:async_hooks:346:14) at /workspace/.next/server/src/middleware.js:13:32383 at /workspace/.next/server/src/middleware.js:13:20903
DEFAULT 2024-11-12T17:17:43.292955Z Missing or malformed credentials { reason: 'MISSING_CREDENTIALS' }
Thanks for sharing the logs @nolafs.
Can I ask you also to share your middleware.ts file?
import {NextRequest, NextResponse} from "next/server";
import {authMiddleware, redirectToHome, redirectToLogin} from "next-firebase-auth-edge";
import {clientConfig, serverConfig} from "./config";
const PUBLIC_PATHS = ['/register', '/login'];
export async function middleware(request: NextRequest) {
console.info('Request to', serverConfig);
return authMiddleware(request, {
debug: serverConfig.debug,
loginPath: "/api/login",
logoutPath: "/api/logout",
apiKey: clientConfig.apiKey,
cookieName: serverConfig.cookieName,
cookieSignatureKeys: serverConfig.cookieSignatureKeys,
cookieSerializeOptions: serverConfig.cookieSerializeOptions,
serviceAccount: serverConfig.serviceAccount,
handleValidToken: async ({token, decodedToken, customToken}, headers) => {
console.info('Authenticated', token, decodedToken, customToken);
// Authenticated user should not be able to access /login, /register and /reset-password routes
if (PUBLIC_PATHS.includes(request.nextUrl.pathname)) {
return redirectToHome(request);
}
return NextResponse.next({
request: {
headers
}
});
},
handleInvalidToken: async (reason) => {
console.info('Missing or malformed credentials', {reason});
return redirectToLogin(request, {
path: '/login',
publicPaths: PUBLIC_PATHS
});
},
handleError: async (error) => {
console.error('Unhandled authentication error', {error});
return redirectToLogin(request, {
path: '/login',
publicPaths: PUBLIC_PATHS
});
}
});
}
export const config = {
matcher: [
"/",
"/((?!_next|api|.*\\.).*)",
"/api/login",
"/api/logout",
],
};
export const serverConfig = {
debug: true,
cookieName: process.env.AUTH_COOKIE_NAME!,
cookieSignatureKeys: [process.env.AUTH_COOKIE_SIGNATURE_KEY_CURRENT!, process.env.AUTH_COOKIE_SIGNATURE_KEY_PREVIOUS!],
cookieSerializeOptions: {
path: "/",
httpOnly: true,
secure: process.env.USE_SECURE_COOKIES === "true",
sameSite: "lax" as const,
maxAge: 12 * 60 * 60 * 24,
},
serviceAccount: {
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!,
clientEmail: process.env.FB_ADMIN_CLIENT_EMAIL!,
privateKey: process.env.FB_ADMIN_PRIVATE_KEY?.replace(/\\n/g, "\n") || "",
}
};
type ClientConfigType = {
projectId?: string;
apiKey: string;
authDomain?: string;
databaseURL?: string;
messagingSenderId?: string;
}
export const clientConfig: ClientConfigType = {
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID
};
There is actually no issue within your code. You just need to remove the console.info
statement
handleInvalidToken: async (reason) => {
- console.info('Missing or malformed credentials', {reason});
handleInvalidToken
is called when something expected happens. One of those expected events is user seeing your app for the first time, or after cookies are expired
Sure, and my local version does work as expected. The deployed version does not redirect at all and when try opening root, it just redirects me back to the login. I can see the cookie but it seems it is not reading it at all. I get simple ?redirect=%2F and it stays on the login after submitting.
If you're using Firebase Hosting, probably worth checking out this issue: #146
Does authentication work if you change cookieName
to __session
?
Doh, I seen that issue earlier and just ignored it. Sorry, thanks for your help.