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

Redirect to custom credential sign in page using ServersideProps requires submitting twice to login #2426

Closed
sabi-wabi opened this issue Jul 26, 2021 · 11 comments
Labels
bug Something isn't working

Comments

@sabi-wabi
Copy link

Description 🐜

There is already a discussion opened for this issue, but it seems to be stagnant.

  • I have a custom credential sign-in page at auth/signin
  • Logic built in to redirect all pages to /auth/signin using getServerSideProps if no user found in session

When submitting the form for the first time, the page will reload and nothing happens.

Is this a bug in your own project?

No

How to reproduce ☕️

Here is the repository to reproduce the issue

  1. Make sure that all cookies are cleared
  2. Direct to http://localhost:3000/
  3. The redirection will happen and will redirect you to http://localhost:3000/auth/signin?callbackUrl=http://localhost:3000
  4. When submitting for the first time, the page will reload and flash, but no redirection to the index page will happen
  5. Submitting it for the second time will work

On an unrelated note, I noticed that it is possible to see the submitted form inputs in the Network tab, is this not a security vulnerability?

image

Screenshots / Logs 📽

No response

Environment 🖥

System:
OS: macOS 11.4
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 60.74 MB / 16.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.16.1 - /usr/local/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 6.14.12 - /usr/local/bin/npm
Browsers:
Brave Browser: 91.1.26.77
Edge: 92.0.902.55
Safari: 14.1.1
npmPackages:
next: ^11.0.0 => 11.0.1
next-auth: latest => 3.27.3
react: ^17.0.2 => 17.0.2

Contributing 🙌🏽

No, I am afraid I cannot help regarding this

@sabi-wabi sabi-wabi added the bug Something isn't working label Jul 26, 2021
@balazsorban44
Copy link
Member

balazsorban44 commented Jul 26, 2021

Not a security vulnerability, since it's using a post method. You should make sure the page is using https in production yourself.

@sabi-wabi
Copy link
Author

Okay thanks for the clarification, how about the issue that I am reporting? Is this something you are able to comment on...?

@balazsorban44
Copy link
Member

Will do when I have the time! 😊

@sastraxi
Copy link

sastraxi commented Aug 8, 2021

@sabi-wabi I was unable to reproduce! Here's what I did:

  1. Cloned the repository
  2. cd next-auth-example && yarn
  3. echo "NEXTAUTH_URL=http://localhost:3000" > .env.local
  4. Tried to log in with any username / password (given that the user is hardcoded)

I was able to login with just one press of the submit button. There didn't appear to be any reload first, nor did I need to click the button twice to get logged in. I was then able to see the hardcoded user logged-in, and was able to log out successfully.

I suggest you might play around with your .env.local to see if there's anything in there causing a mess!

@denkristoffer
Copy link

denkristoffer commented Nov 10, 2021

I am also seeing this issue using the v4 beta, the email provider and a custom sign in page. It doesn't happen every time, but often enough that it's annoying. I will try to see if I can get to the bottom of what's going on.

@kudziajaroslaw98
Copy link

kudziajaroslaw98 commented Dec 14, 2021

I have the same problem with the next-auth ^4.0.5 version. The only thing I caught is that the first time I'm redirected to the login page I have a link like this
http://localhost:3000/auth/signin?callbackUrl=http://localhost:3000
after the first try to login, the page changed its URL to
http://localhost:3000/auth/signin?#
and after this one change I can log in in the first attempt.
It's working even if I just type /auth/signin?# by myself or after this one click on submit button.

EDIT:
everything seems to work fine when instead of using signIn() function on login button
async function signInHandler() { await signIn() }
I redirect user to exactly /auth/signin?# path
async function signInHandler() { Router.push('/auth/signin?#'); }

@mannybatth
Copy link

I'm running into the same issue with the EmailProvider (password less sign in). The sign in page redirects to /auth/signin?callbackUrl=http://localhost:3000 on the first login attempt and forces you to resubmit again.

@mannybatth
Copy link

mannybatth commented Mar 3, 2022

Seems like this issue only happens when calling getCsrfToken in getServerSideProps. I moved getCsrfToken into getInitialProps and never ran into the redirect.

Sample:

SignIn.getInitialProps = async (context) => {
    const { req, res } = context;
    const session = await getSession({ req });

    if (session && res && session.user) {
        res.writeHead(302, {
            Location: '/',
        });
        res.end();
        return;
    }

    return {
        csrfToken: await getCsrfToken(context),
        error: context.query.error,
    };
};

@magnusdr
Copy link

I was experiencing this both in production and development. The silent failure on first attempt was caused by the csrfToken in my login form to be mismatching the one in my browser's cookie.

In development, I can see that calls to /api/auth/session is setting the next-auth.csrf-token cookie. I was generating a csrfToken using getCsrfToken() in my getServerSideProps, and this caused my server side rendered login form to be incoherent with the next-auth.csrf-token cookie. When a subsequent request to api/auth/session was made with no cookie, my browser got a cookie, still not matching the one in my login form.

On Vercel, the /api/auth/session responses is not setting thenext-auth.csrf-token cookie. In this case, it was mismatching simply because I did not have any next-auth.csrf-token cookie when requesting /api/auth/signin. I guess I could set the cookie myself inside getServerSideProps using context.res.setHeader(), but I'm not sure what other effects that might have, so I went with using the documented getCsrfToken() function client side.

TLDR; for me, the fix was simple: don't provide csrfToken as a prop with getServerSideProps, but fetch it in your login component client side. Would be nice if this didn't fail silently, at least not during development.

const Login = () => {
  const session = useSession();
  const [csrfToken, setCsrfToken] = useState('');

  useEffect(() => {
    async function fetchCsrfToken() {
      const result = await getCsrfToken();
      if (!result) {
        throw new Error('Can not sign in without a CSRF token');
      }
      setCsrfToken(result);
    }

    /*
      Wait until session is fetched before obtaining csrfToken 
      to prevent synchronization issues caused by both 
      /api/auth/session and /api/auth/csrf setting the cookie. 
      Only happens in dev environment.
    */
    if (session.status !== 'loading') {
      fetchCsrfToken();
    }
  }, [session.status]);

  return <form>
    {/* Hiding the rest for brevity */}
  </form>
}

@thomasmost
Copy link

@magnusdr Thank you!!

@ThangHuuVu
Copy link
Member

Sorry for the late revisiting - in the issue description, I see that OP was using getSession on the server. This is not recommended anymore as we have provided a getServerSession to use on the server side. If anyone is still having this issue, feel free to reopen a new issue with a working reproduction. Closing this one for now 🙇‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants