awinogrodzki / next-firebase-auth-edge

Next.js Firebase Authentication for Edge and Node.js runtimes. Compatible with latest Next.js features.
https://next-firebase-auth-edge-docs.vercel.app/
MIT License
524 stars 44 forks source link

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

Closed rustyspottedcatt closed 2 weeks ago

rustyspottedcatt commented 2 months ago

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
  2. 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.
  3. Code:

import { authMiddleware, redirectToLogin } from "next-firebase-auth-edge"; import type { NextRequest } from "next/server";

export async function middleware(request: NextRequest): Promise { 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"], };

4. 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:**

```shell
❯ 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
awinogrodzki commented 2 months ago

Hey @rustyspottedcatt!

Thanks for reporting. Looks like the same issue as https://github.com/awinogrodzki/next-firebase-auth-edge/issues/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

awinogrodzki commented 2 months ago

@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"
}
awinogrodzki commented 2 months ago

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

awinogrodzki commented 2 months ago

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

giulioco commented 2 months ago

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

awinogrodzki commented 1 month ago

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

bySegunMoses commented 1 month ago

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

awinogrodzki commented 1 month ago

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?

awinogrodzki commented 2 weeks ago

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