Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: no matching decryption secret #10633

Open
zmzlois opened this issue Apr 18, 2024 · 30 comments
Open

Error: no matching decryption secret #10633

zmzlois opened this issue Apr 18, 2024 · 30 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@zmzlois
Copy link

zmzlois commented Apr 18, 2024

Environment

System:
OS: macOS 14.2.1
CPU: (12) arm64 Apple M2 Pro
Memory: 245.33 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.11.0 - /usr/local/bin/node
Yarn: 1.22.21 - /usr/local/bin/yarn
npm: 10.2.4 - /usr/local/bin/npm
pnpm: 8.7.6 - /usr/local/bin/pnpm
bun: 1.0.35 - /usr/local/bin/bun
Browsers:
Chrome: 124.0.6367.61
Safari: 17.2.1
npmPackages:
next: 14.2.2 => 14.2.2
next-auth: ^5.0.0-beta.16 => 5.0.0-beta.16
react: ^18 => 18.2.0

Reproduction URL

https://github.com/zmzlois/next-auth-repro

Describe the issue

Under this set up, I constantly have this error
Screenshot 2024-04-18 at 16 35 22

How to reproduce

git clone https://github.com/zmzlois/next-auth-repro

and set environment varible secrets for AUTH_SECRET, AUTH_TWITTER_ID and AUTH_TWITTER_SECRET

Click on the sign in button on first page

Expected behavior

After sign in, I should be redirected to dashboard if I am in, the auth secret is generated by npx auth secret and stored in .env file

@zmzlois zmzlois added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Apr 18, 2024
@zmzlois
Copy link
Author

zmzlois commented Apr 18, 2024

There is a second branch second if you checkout on that branch the error will then be different:
Screenshot 2024-04-18 at 16 48 53

@mwawrusch
Copy link
Contributor

mwawrusch commented Apr 20, 2024

I have the same issue, in two different projects.

[auth][error] JWTSessionError: Read more at https://errors.authjs.dev#jwtsessionerror
[auth][cause]: Error: no matching decryption secret
    at clockTolerance (webpack-internal:///(rsc)/../../node_modules/next-auth/node_modules/@auth/core/jwt.js:87:15)
    at async flattenedDecrypt (webpack-internal:///(rsc)/../../node_modules/jose/dist/node/esm/jwe/flattened/decrypt.js:106:15)
    at async compactDecrypt (webpack-internal:///(rsc)/../../node_modules/jose/dist/node/esm/jwe/compact/decrypt.js:22:23)
    at async jwtDecrypt (webpack-internal:///(rsc)/../../node_modules/jose/dist/node/esm/jwt/decrypt.js:12:23)
    at async Object.decode (webpack-internal:///(rsc)/../../node_modules/next-auth/node_modules/@auth/core/jwt.js:78:25)
    at async Module.session (webpack-internal:///(rsc)/../../node_modules/next-auth/node_modules/@auth/core/lib/actions/session.js:23:29)
    at async AuthInternal (webpack-internal:///(rsc)/../../node_modules/next-auth/node_modules/@auth/core/lib/index.js:47:24)
    at async Auth (webpack-internal:///(rsc)/../../node_modules/next-auth/node_modules/@auth/core/index.js:126:34)
    at async getCurrentUser (webpack-internal:///(rsc)/./src/domains/security/getCurrentUser.ts:8:21)
    at async $$ACTION_0 (webpack-internal:///(rsc)/./src/domains/security/serverValidateAccess.ts:22:18)
    at async Layout (webpack-internal:///(rsc)/./src/app/(public)/layout.tsx:25:18)
[auth][details]: {}

@gustaveWPM
Copy link

gustaveWPM commented Apr 21, 2024

There's definitely an issue with secret handling in Auth.js v5.0.0-beta.16

I encountered this error and also other weird things.
Currently, I'm having an infinite loop, occuring in the middleware.

image

I've noticed that it could come from the Config object.

import type { NextAuthConfig } from 'next-auth';

import Discord from 'next-auth/providers/discord';
import { getSession } from '@/auth';

const AUTH_SECRETS_SEP = ';;;;;;';

const secret = process.env.AUTH_SECRETS!.split(AUTH_SECRETS_SEP);

const config = {
  providers: [
    Discord({
      authorization: {
        params: {
          scope: 'identify+guilds'
        }
      },
      clientSecret: process.env.DISCORD_CLIENT_SECRET ?? '',
      clientId: process.env.DISCORD_CLIENT_ID ?? ''
    })
  ],

  callbacks: {
    async session({ session }) {
      const s = await getSession(session);
      return s;
    }
  },

  secret
} as const satisfies NextAuthConfig;

console.log(config.secret);

export default config;

Here, I get an error intercepted by my IDE: process.env.AUTH_SECRETS is undefined
( ⚠️ Notice the trailing "S" in AUTH_SECRETS in this code snippet.)

This is super weird.
I don't understand why.

Now, if I just do this:

const secret = "hummmmm";

// * ...

  callbacks: {
    async session({ session }) {
      const s = await getSession(session);
      return s;
    }
  },

  secret
} as const satisfies NextAuthConfig;

Then, everything works properly. oO

I'm curious, is this happening in your projects too?
I don't think this is the right way to solve the problem. Especially as my project is open source and I want to keep it that way... Hard-coding a secret is an huge footgun.

https://github.com/Tirraa/dashboard_rtm/blob/next-auth-v5-and-bentocache-exit/src/config/auth.ts

Btw, cloning the repo and going on the next-auth-v5-and-bentocache-exit branch to reproduce this should be easy.

Once you're on the branch, simply run make initialize && make && make start, or make initialize && make dev.

(Don't forget to remove the hardcoded secret value in @/src/config/auth)

Running this project is pretty straightforward. (It's intended to become a full-features template...)
You just need to edit the autogenerated (via make initialize) .env file to put Discord creds in it. But I think it could go in an infinite loop even without doing so.


Furthermore, I think that when I tested WITHOUT the navbar login button on my site, there was no infinite loop.

It can be tested easily, just editing this file:
https://github.com/Tirraa/dashboard_rtm/blob/next-auth-v5-and-bentocache-exit/src/config/SitewideNavbar/Extras/utils/ComponentsMapping.tsx

And replacing <NavbarLoginButton {...} /> with a <div />

I'm double checking this.

Maybe there's an insidious problem with the useSession hook? I don't know.

EDIT:
Yes, indeed, this infinite loop vanishes when removing the <NavbarLoginButton /> component, as when hard-coding the secret value in the config file.

But when I remove the <NavbarLoginButton /> component (still using a hard-coded secret value), I've also the Error: no matching decryption secret which is raised.

Super weird.


Some help would be very appreciated!
I'm really lost concerning this bug. :(

Also maybe related to: #10478
(Not occuring during the build but in the runtime, concerning my project)


EDIT (2): Lmao, what's going on?

Exporting anything else than the export default from my config file results in:

image

Sounds more and more like an underlying client/server issue in the current implementation.


EDIT (3):

Okay...

const secret = process.env.AUTH_SECRETS?.split(AUTH_SECRETS_SEP) ?? 'NTM';
// * ...
if (config.secret === 'NTM') console.log('Secret is NTM!');

image

It looks like the current implementation sometimes try to access process.env ON THE CLIENT, which will never work. (Notice that putting a AUTH_SECRET variable in the .env and omitting the secret value in the config results in a MissingSecret error, which is likely very similar to what I pointed out here.)

I think we should have a separated config for server and client purposes, and to ensure that the config on the server is frozen and only initialized once.

It also worries me, the secret value seems to be not so much isolated on the server side.

@ndom91
Copy link
Member

ndom91 commented Apr 21, 2024

Hmm so these should be working.. Our example apps with the latest version have variations of all of these that work.

@zmzlois in your repro, it looks like your custom SessionProvider you wrote is causing the infniite redirect loop. Should be somethign like this (pseudocode, not 100% sure abotu the next.js router details):

import { ReactNode } from "react";
import { auth } from "@/auth";
import { useRouter, redirect } from "next/navigation";

export const SessionProvider = async ({
  children,
}: Readonly<{ children: ReactNode }>) => {
  const session = await auth();
+  const router = useRouter();

-  if (!session) {
+  if (!session && router.pathname !== "/api/auth/signin") {
-    return redirect("/");
+    return redirect("/api/auth/signin");
  }

  if (session) {
    return <>{children}</>;
  }
};

@gustaveWPM in your latest repro the import config from "@/config/auth" doesn't seem to be resolving correctly.

Generally, you don't have to pass a secret or anything additionally. As long as you have AUTH_SECRET defined in your .env (or platform environment variables, like in Vercel or Netlify), you should be good to go.

@gustaveWPM
Copy link

Hmm so these should be working.. Our example apps with the latest version have variations of all of these that work.

@zmzlois in your repro, it looks like your custom SessionProvider you wrote is causing the infniite redirect loop. Should be somethign like this:

import { ReactNode } from "react";
import { auth } from "@/auth";
import { useRouter, redirect } from "next/navigation";

export const SessionProvider = async ({
  children,
}: Readonly<{ children: ReactNode }>) => {
  const session = await auth();
+  const router = useRouter();

-  if (!session) {
+  if (!session && router.pathname !== "/api/auth/signin") {
-    return redirect("/");
+    return redirect("/api/auth/signin");
  }

  if (session) {
    return <>{children}</>;
  }
};

@gustaveWPM in your latest repro the import config from "@/config/auth" doesn't seem to be resolving correctly.

Generally, you don't have to pass a secret or anything additionally. As long as you have AUTH_SECRET defined in your .env (or platform environment variables, like in Vercel or Netlify), you should be good to go.

image

@ndom91
Copy link
Member

ndom91 commented Apr 21, 2024

That's not very helpful, did yuo figure out the config issue? It's still throwing MissingSecret? Unfortunately I can't dive through your entire application, but if you can provide a minimal reproduction, we can take a closer look 🙏

@gustaveWPM

This comment was marked as spam.

@gustaveWPM
Copy link

gustaveWPM commented Apr 21, 2024

Passing the session from the server to the <SessionProvider /> fixes the infinite loop.
However, it breaks SSG on all the pages using <SessionProvider />, which is highly undesirable.

In v4, it was possible to use <SessionProvider> without specifying a session inside and getting it work properly via the API endpoint, to preserve the SSG.

EDIT: I think I'll manage my integration, but I'll have to use a lot of counter-intuitive "Tricks"...


Doing this:

import { useSession, signOut } from 'next-auth/react';

  // * ...

  const pathname = usePathname();
  const whatever = isProtectedRoute(pathname) ? { callbackUrl: ROUTES_ROOTS.WEBSITE, redirect: true } : undefined;

// * ...

<button onClick={() => {
  signOut(whatever);
}}
>
// * ...

Causes the MissingSecret error.
The exact same, but without anything conditional in the parameters of signOut works.


EDIT (final): finally, I managed to implement exactly what I wanted by sticking to Next Auth v4.
As v5 is completely unusable, I abandoned any project of migrating to it and deleted the associated branches from my project. My reproduction is no longer available.

@ablosser-wvuf
Copy link

Just wanted to pop in here and say I'm having the exact same issue on a previously working codebase, I believe it stopped working after an npm update but I'm not 100% on that.

Is the original posters repo not slim enough for triage / debugging? If not I can try and make a tiny one if that's helpful, I'm not entirely sure exactly what you need for this.

@ndom91
Copy link
Member

ndom91 commented Apr 27, 2024

The main problem is that so many custom thing's have been done above that its hard to find what might be wrong.

v5 is designed primarily to be used with next 14 and server components, so part of the issue seems like you guys are working very hard against next 14 and auth.js v5.

Anyway, the example app has both working server components and a client component example page (https://next-auth-example.vercel.app).

If youre having a specific issue, a minimal reproduction is immensely helpful for us to nail down any potential issue with auth.js. Not only because through making a minimal reproduction you usually find out if you yourself made an oopsie, but if there is an issue with auth.js we can then easily pinpoint it and fix it 🙏

@ThangHuuVu
Copy link
Member

@zmzlois I tried your reproduction but couldn't reproduce the issue. There are two things I have to change in your code before running:

  1. Comment out the code that causes the infinite loop issue that @ndom91 pointed out above
  2. Delete the twitter/callback route you defined (this overrides our next-auth route)
Screenshot 2024-04-28 at 09 44 13

Is there anything missing in your reproduction that could cause the issue?

@mwawrusch
Copy link
Contributor

So this is becoming a problem for me as I had to delay the go-live of a site because of this bug. What I noticed is that the error does not occur immediately but after either a set time or when the development server is restarted. FYI we use a very standard v14 and server code. What can I do to help you find this bug?

@balazsorban44
Copy link
Member

v5 is designed primarily to be used with next 14 and server components

To clarify, even if the main focus was to treat Server Components/Actions as a first-class citizen, next-auth is still fully compatible with Pages/Client components. The API is exactly the same as it was in v4.

Anyone posting "same issue" here, please add a minimal reproduction. We cannot investigate otherwise. Screenshots of terminal errors or "standard" code is not sufficient. Check out https://github.com/nextauthjs/next-auth-example which is also deployed on https://next-auth-example.vercel.app/ and works correctly.

@mwawrusch
Copy link
Contributor

https://github.com/nextauthjs/next-auth-example

Working my way through that example to figure out the root cause of this. I noticed something, The auth routes are exported both under /api/auth and /auth - is that intentional?

@zmzlois
Copy link
Author

zmzlois commented May 2, 2024

weirdly, I open the repo again and it works now even when I comment out the secret in config like so

export const { handlers, signIn, signOut, auth } = NextAuth({
    providers: [Twitter],
    // secret: "somesupertopsecret",
})

😳??

@mwawrusch
Copy link
Contributor

mwawrusch commented May 3, 2024

Yes, I had the same experience last night. This used to be the code most likely causing the above error:

jwt: {
     secret:  process.env.NEXTAUTH_SECRET,
   } as any,
  secret: process.env.NEXTAUTH_SECRET,

Removing the above and just defining the AUTH_SECRET works.

@Christophvh
Copy link

Christophvh commented May 24, 2024

i'm getting the exact same issue after upgrading to @beta-18

    providers: [
        Resend({
            from: 'auth@resend.dev',
        }),
    ],

the invitation logic is broken suddenly.

@ndom91
Copy link
Member

ndom91 commented May 29, 2024

@Christophvh can you provide some more details about your setup? I was able to use the Resend provider, for exmaple, successfully with our Next.js example app (https://github.com/nextauthjs/next-auth-example) just now

@Christophvh
Copy link

@Christophvh can you provide some more details about your setup? I was able to use the Resend provider, for exmaple, successfully with our Next.js example app (https://github.com/nextauthjs/next-auth-example) just now

beta 18 seems to be fixed. upgrade failed, was still on beta-16. sorry for the confusion!

@abencun-symphony
Copy link

abencun-symphony commented Jul 1, 2024

We're still seeing this completely randomly in Vercel logs of our deployments on Vercel -- we were never able to reproduce it locally. Sometimes it goes away for some time after a fresh deployment rolls but often it's back with the next deployment. Everything has been set up properly for a very long time now, AUTH_SECRET is defined etc. We ran out of ideas, this looks like a major bug, potentially a build time thing because, as I said, some of the deployments seem to be stable sometimes and don't cause this error. We're using the Keycloak provider - but for JWT decoding I don't think that should matter. Next-Auth beta 19. Next 14.2.4.

Would provide a repro repo but, unfortunately, we have no idea how to reproduce this consistently.

@femiabimbola
Copy link

femiabimbola commented Jul 10, 2024

Hi everyone,

I am having the same issue.

Follow the following steps to reproduce the error

git clone https://github.com/femiabimbola/authjs-refresher

npm install

Use postman or thunderbird to sign in after registering a user,

http;//localhost:3000/api/login

@mwawrusch
Copy link
Contributor

Every single day we see this - Makes using the log files while developing a nightmare.

[auth][error] JWTSessionError: Read more at https://errors.authjs.dev#jwtsessionerror
[auth][cause]: Error: no matching decryption secret
    at clockTolerance (webpack-internal:///(action-browser)/../../node_modules/@auth/core/jwt.js:87:15)
    at async flattenedDecrypt (webpack-internal:///(action-browser)/../../node_modules/jose/dist/node/esm/jwe/flattened/decrypt.js:106:15)
    at async compactDecrypt (webpack-internal:///(action-browser)/../../node_modules/jose/dist/node/esm/jwe/compact/decrypt.js:22:23)
    at async jwtDecrypt (webpack-internal:///(action-browser)/../../node_modules/jose/dist/node/esm/jwt/decrypt.js:12:23)
    at async Object.decode (webpack-internal:///(action-browser)/../../node_modules/@auth/core/jwt.js:78:25)
    at async Module.session (webpack-internal:///(action-browser)/../../node_modules/@auth/core/lib/actions/session.js:23:29)
    at async AuthInternal (webpack-internal:///(action-browser)/../../node_modules/@auth/core/lib/index.js:47:24)
    at async Auth (webpack-internal:///(action-browser)/../../node_modules/@auth/core/index.js:126:34)
    at async getCurrentUser (webpack-internal:///(action-browser)/./src/domains/security/getCurrentUser.ts:8:21)
 ...
    
    

@juan-carlos-correa
Copy link

juan-carlos-correa commented Jul 15, 2024

https://next-auth-example.vercel.app

The big issue here is that calling the auth() function like this example, is making the page a dynamic route (since is accessing to cookies), even though the content of the page is 100% static.

const session = await auth()

Is not acceptable to make my app rendering for each request, is slower and expensive.

I got it, this makes sense to be dynamic in Next 14 since using headers or cookies makes a component unable to render statically, makes all the sense of the world.

I'm not working hard against Next 14 or server actions, I'm working hard looking ways to use auth js in my project without making my app 100% dynamic.

I fixed the dynamic rendering getting the user session in the client side, which is acceptable to me.

I think it would be a good idea to have this kind of clarifications in the docs, I'm open to contribute.

For example: anti patterns and solutions:

  • Using auth() in the RootLayout because will convert your full app rendered dynamically. Instead, use client side auth identification and middleware for restricting access to private routes.
  • Using auth() in a layout or page when you intend to render statically the content -> use client side auth identification, this at least will let you pre render the page as HTML.
  • Using auth in the Next.js middleware when you are working with Node.js modules. For now, middleware is an edge function. Workaround: use api calls for now.

Those points were a really big headaches to me, gladly I found workarounds for making them work properly.

Again, I'm open to contribute with examples in the docs!

@mwawrusch
Copy link
Contributor

Some examples would be awesome, docs or otherwise. The amount of hours wasted on nextauth is mindboggling

@ndom91
Copy link
Member

ndom91 commented Jul 21, 2024

The issue no matching decryption secret comes from when we try to decode the JWT. So that means there's something along the line wrong with the AUTH_SECRET environment variable. Maybe it isn't available in your environment on the server side, maybe you're defining it twice in the root of the config and once more under jwt as some other folks above have pointed out might be an issue.

But again, without minimal reproductions it's really hard for us to find more specific issues that might be wrong.


@juan-carlos-correa we still provide the client side methods like we did in v4, see: https://authjs.dev/getting-started/session-management/login and click "Next.js (Client)"


@mwawrusch are the examples / docs at authjs.dev not sufficient? If you're stuck on a specific problem, again, a minimal reproduction would be great..


Personal opinion: as some of you have mentioned you weren't able to consistently reproduce the issue in order to even create a minimal reproduction. Based on what I've read in this thread and what I know building and maintaining auth.js applications over the years, I have a hunch the issue may lie in that the secret environment variable isn't always available from your hosting environment in all environments, i.e. in serverless functions, normal long-lived API processes, etc.

@abencun-symphony
Copy link

abencun-symphony commented Jul 22, 2024

In our case this is the current state of things:

  • This has never ever happened before prior to us moving to v5 beta a couple of months ago
  • We set the secret explicitly in NextAuthConfig, are you saying that we should not?
  • We can't seem to be able to reproduce it locally, only on deployments (Vercel)
  • AUTH_SECRET is always defined seeing that we deploy using Vercel and it's in our Environment Variables and everything is running fine on all of our environments, including prod - except for when this error shows up randomly
  • Sometimes random new deployments kinda fix it for a while - then it just comes back randomly after a couple hours or days. Maybe this is an issue with Vercel caching or doing something else wrong since we're now using auth in middleware, while we previously didn't use any of the middleware stuff in v4?

@ndom91
Copy link
Member

ndom91 commented Jul 22, 2024

@abencun-symphony thanks for the further info. Regarding

  • We set the secret explicitly in NextAuthConfig, are you saying that we should not?

I was just referring to comments above, like this one, who mentioned somethign like diff helped them:

export const { ... } = NextAuth({
  ...
-  jwt: {
-    secret: 'abc123'
-  },
  secret: 'abc123'
})

THe rest of your bullet point do sound to me like either next-auth isn't picking up the AUTH_SECRET sometimes, or it just isn't available sometimes 🤔

@mwawrusch
Copy link
Contributor

The issue no matching decryption secret comes from when we try to decode the JWT. So that means there's something along the line wrong with the AUTH_SECRET environment variable. Maybe it isn't available in your environment on the server side, maybe you're defining it twice in the root of the config and once more under jwt as some other folks above have pointed out might be an issue.

But again, without minimal reproductions it's really hard for us to find more specific issues that might be wrong.

@juan-carlos-correa we still provide the client side methods like we did in v4, see: https://authjs.dev/getting-started/session-management/login and click "Next.js (Client)"

@mwawrusch are the examples / docs at authjs.dev not sufficient? If you're stuck on a specific problem, again, a minimal reproduction would be great..

Personal opinion: as some of you have mentioned you weren't able to consistently reproduce the issue in order to even create a minimal reproduction. Based on what I've read in this thread and what I know building and maintaining auth.js applications over the years, I have a hunch the issue may lie in that the secret environment variable isn't always available from your hosting environment in all environments, i.e. in serverless functions, normal long-lived API processes, etc.

I sent some repo months ago. We run this on vercel, so that's as close to source as it gets.
My hunch is that there are problems between server/client code and because there is only one entry point (auth) things get mixed up. Someone pointed this out in this or another thread a few months ago.

I have various projects with nextauth, and sometimes I get lucky, sometimes I don't

@abencun-symphony
Copy link

@ndom91 Yeah, we tried both adding and removing the jwt.secret field, that didn't help in our case.

@tomphill
Copy link

Weirdly I was able to reproduce this issue on local (macbook air m1) using the bare minimal setup with the Credentials provider but only with certain conditions. If I run 2 separate applications, one on localhost:3000 and one on localhost:3001. Log in to both apps. Refresh them both, then I see the error:
JWTSessionError
Error: no matching decryption secret

Tested with a combination of Next JS 14.2.5 & 15.0.0-rc.0,
with next-auth 5.0.0-beta.19 & 5.0.0-beta.20.

If I'm only running 1 app on localhost I don't get this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests