awinogrodzki/next-firebase-auth-edge

TypeError: Key for the RS256 algorithm must be of type CryptoKey. Received an instance of Uint8Array

rustyspottedcatt opened this issue · 9 comments

Description:

I’m encountering a TypeError when attempting to verify cookies using the RS256 algorithm in a Next.js middleware. The error occurs when I pass cookieSignatureKeys to the authMiddleware.

Error Stack:

⨯ Error [TypeError]: Key for the RS256 algorithm must be of type CryptoKey. Received an instance of Uint8Array
    at asymmetricTypeCheck (webpack-internal:///(middleware)/./node_modules/jose/dist/browser/lib/check_key_type.js:22:15)
    at checkKeyType (webpack-internal:///(middleware)/./node_modules/jose/dist/browser/lib/check_key_type.js:49:9)
    at flattenedVerify (webpack-internal:///(middleware)/./node_modules/jose/dist/browser/jws/flattened/verify.js:88:71)
    at compactVerify (webpack-internal:///(middleware)/./node_modules/jose/dist/browser/jws/compact/verify.js:22:97)
    at jwtVerify (webpack-internal:///(middleware)/./node_modules/jose/dist/browser/jwt/verify.js:12:97)
    at verifyCustomJWT (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/lib/auth/custom-token/index.js:26:33)
    at RotatingCredential.verify (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/lib/auth/rotating-credential.js:19:73)
    at parseTokens (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/lib/auth/cookies/sign.js:59:41)
    at getRequestCookiesTokens (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/lib/next/tokens.js:38:35)
    at authMiddleware (webpack-internal:///(middleware)/./node_modules/next-firebase-auth-edge/lib/next/middleware.js:112:73)

What I have tried:

  1. Environment Setup:
  • Next.js version: 14+
  • next-firebase-auth-edge version: ^1.7.0-canary.15
  • Node.js version: v20.16.0
  1. Troubleshooting Steps Taken:
  • I tried different versions of next-firebase-auth-edge and jose.
  • Manually converted cookieSignatureKeys to CryptoKey using the Web Crypto API, but the error persisted.
  • Used placeholders for the cookieSignatureKeys and simplified the setup, but the same error occurs.
  • Redid the Firebase setup from scratch, ensuring all keys and configs are properly set.
  1. Code:
import { authMiddleware, redirectToLogin } from "next-firebase-auth-edge";
import type { NextRequest } from "next/server";

export async function middleware(request: NextRequest): Promise<Response> {
  try {
    return authMiddleware(request, {
      loginPath: "/api/login",
      logoutPath: "/api/logout",
      apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY as string,
      cookieName: "AuthToken",
      enableMultipleCookies: false,
      debug: true,
      cookieSignatureKeys: [
        process.env.COOKIE_SECRET_CURRENT!,
        process.env.COOKIE_SECRET_PREVIOUS!,
      ],
      cookieSerializeOptions: {
        path: "/",
        httpOnly: true,
        secure: process.env.NODE_ENV === "production",
        sameSite: "lax",
        maxAge: 24 * 60 * 60 * 1000,
      },
      serviceAccount: {
        ...JSON.parse(
          JSON.stringify(process.env.NEXT_PRIVATE_FIREBASE_ACCOUNT) as string
        ),
      },
      handleError: async (error) => {
        console.error("Middleware error:", error);
        return redirectToLogin(request, {
          path: '/login',
          publicPaths: ['/login', '/signup'],
        })
      },

    });
  } catch (error) {
    console.error("Middleware error:", error);
    return new Response("Internal Server Error", { status: 500 });
  }
}

export const config = {
  matcher: ["/dashboard"],
};
  1. Identified Issue
  • The error seems to stem from the cookieSignatureKeys when passed to jose, which expects them to be in CryptoKey format. I’ve tried converting them manually, but this hasn’t resolved the issue.
  • It appears Uint8Array is being passed, but CryptoKey is expected.

Expected Behavior:
I expect the cookieSignatureKeys to work without throwing a TypeError, allowing for cookie signing.
Actual Behavior:
The middleware throws a TypeError indicating that the key must be of type CryptoKey, but it receives a Uint8Array instead. Despite multiple efforts to resolve it, I am unable to pass the correct CryptoKey format.

npx next info:

❯ npx next info

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 16086
  Available CPU cores: 12
Binaries:
  Node: 20.16.0
  npm: N/A
  Yarn: N/A
  pnpm: 9.9.0
Relevant Packages:
  next: 14.2.9 // Latest available version is detected (14.2.9).
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.5.4
Next.js Config:
  output: N/A

Hey @rustyspottedcatt!

Thanks for reporting. Looks like the same issue as #242

It seems the TextEncoder did not help to solve the issue.

Also, it seems to be connected with JOSE implementation in Windows.

Let me look for some answers and I'll get back to you

@rustyspottedcatt can I ask you to debug the authentication cookie in https://jwt.io/ and tell me the value of headers?

It should look like this:

{
  "alg": "HS256",
  "typ": "JWT"
}

jwtVerify method should be called with a token signed with HS256 algorithm. For some reason jose interprets the token as RS256.RS256 algorithm requires asymmetric key in the form of KeyObject, hence the error.

Knowing the header would help me identify if there's issue in jwtVerify method or wrong algorithm is used before setting authentication cookies

Also, please let me know if the authentication cookie contains : character when you paste it to https://jwt.io

What is the value of enableMultipleCookies that you pass in middleware? Have you changed this option from true to false?

There are two specific scenarios where user can fall into this error:

Scenario 1:

  1. User logs in to app with enableMultipleCookies: true
  2. Developer changes configuration to enableMultipleCookies: false
  3. User deletes ${cookieName}.sig and ${cookieName}.custom headers, but keeps ${cookieName} header
  4. User tries to open app

Scenario 2:

  1. App is configured with enableMultipleCookies: true
  2. Server strips ${cookieName}.sig and ${cookieName}.custom headers, but leaves only ${cookieName} header

I am not sure if that's the case you did hit. Have you tried to remove the cookies and log in again? Do you keep getting the same result?

I have prepared a fix for the cases I mentioned: https://github.com/awinogrodzki/next-firebase-auth-edge/pull/256/files
It will redirect to handleInvalidToken and log a descriptive debug message when user with multiple cookies tries to enter single cookie flow

Also seeing the same issue. When I debugged the token I see

{
  "alg": "RS256",
  "kid": "_aLBDQ"
}

To create the session cookie, I just auth.createSessionCookie (auth being firebase-admin auth()`

I'm on the latest version 1.7.1

Hey @giulioco,

The library is not compatible with auth.createSessionCookie. The library creates, manages and validates session cookie in format that differs from the one returned by auth.createSessionCookie. I might add createSessionCookie support in future versions

Hello @awinogrodzki I'm currently having this issue, any solutions yet?

Hey @bySegunMoses,

Could you run npx next info and share the output here?

What version of the library are you using?

Could you share your middleware.ts file?

Are you using enableMultipleCookies option?

Could you share the stack trace of the error that you're having?

I will close the issue now due to lack of responsiveness.

If anyone else encounters this issue, please create a new one and provide all the details mentioned in previous comment to speed up the resolution