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

Beta 6 upgrade breaking callback error definition #3106

Closed
NuroDev opened this issue Nov 3, 2021 · 7 comments
Closed

Beta 6 upgrade breaking callback error definition #3106

NuroDev opened this issue Nov 3, 2021 · 7 comments
Labels
bug Something isn't working

Comments

@NuroDev
Copy link

NuroDev commented Nov 3, 2021

Description 🐜

Currently running a Next.js project using next-auth version 4.0.0-beta.4 & @next-auth/prisma-adapter version 0.5.2-next.19 (Though I don't feel this dependency is relevant here I am just making it aware I am using it).

I have my [...nextauth].ts file set up with a custom pages object that points error pages to the same page as my sign in page (So I can instead use a toast to prompt the error).

I upgraded my project to v6 & so far the only bug I have noticed is that any callback failures of any kind (Callback failure, OAuth account not linked, etc) get returned as undefined.

Since I am using Vercel I checked my functions logs and saw the following (As an example):

[GET] /auth/signin?error=undefined                                  20:57:38:40
[GET] /api/auth/error?error=OAuthAccountNotLinked                   20:57:38:29

So somewhere, either by an issue on my end or a bug that slipped through in the new release errors are not getting passed back correctly.

Is this a bug in your own project?

No

How to reproduce ☕️

import NextAuth from 'next-auth';
import DiscordProvider from 'next-auth/providers/discord';

export default NextAuth({
	adapter: PrismaAdapter(prisma),
	pages: {
		error: '/auth/signin',
		signIn: '/auth/signin',
		// ...
	},
	providers: [
		// Using Discord as it allows you to abort a sign-in
	  DiscordProvider ({
		    clientId: process.env.DISCORD_CLIENT_ID,
			clientSecret: process.env.DISCORD_CLIENT_SECRET,
	  }),
	],
	secret: process.env.AUTH_SECRET,
});

Attempt to login in via Discord and click "Cancel" & you should be re-directed back to:

[NEXTAUTH_URL_HERE]/auth/signin?error=undefined

You should be navigated to:

[NEXTAUTH_URL_HERE]/auth/signin?error=Callback

Screenshots / Logs 📽

No response

Environment 🖥

Note: I am running Windows 11, not Windows 10 (Bug with Node.js)

  System:
    OS: Windows 10 10.0.22000
    CPU: (24) x64 AMD Ryzen 9 5900X 12-Core Processor
    Memory: 19.48 GB / 31.92 GB
  Binaries:
    Node: 16.13.0 - ~\AppData\Local\Temp\fnm_multishells\31248_1635963610945\node.EXE
    Yarn: 1.22.15 - G:\apps\yarn\current\Yarn\bin\yarn.CMD
    npm: 8.1.0 - ~\AppData\Local\Temp\fnm_multishells\31248_1635963610945\npm.CMD
  Browsers:
    Edge: Spartan (44.22000.120.0), Chromium (95.0.1020.40)
    Internet Explorer: 11.0.22000.120
  npmPackages:
    next: ^12.0.2 => 12.0.2 
    next-auth: ^4.0.0-beta.6 => 4.0.0-beta.6 
    react: ^17.0.2 => 17.0.2 

Contributing 🙌🏽

Yes, I am willing to help solve this bug in a PR

@NuroDev NuroDev added the bug Something isn't working label Nov 3, 2021
@balazsorban44
Copy link
Member

Most probably introduced by #2857 by mistake. that PR was huge. will have a look later, thanks.

sidenote, I don't think we ever handled signin canceling.

#1820

@jasonjei
Copy link

jasonjei commented Nov 5, 2021

@balazsorban44 @NuroDev

Also receiving the same issue with next-auth 4.0.0-beta.6. I'm using custom sign-in, sign-out, and error pages in my [...nextauth].js. Every error is being sent to my error page as /auth/error?error=undefined. Doesn't matter if it's oauth, credentials, etc--happens when you're using custom error pages.Screen Shot 2021-11-05 at 12 43 57 PM

How to reproduce ☕️

[...nextauth].js

import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
import FacebookProvider from 'next-auth/providers/facebook'
import CredentialsProvider from 'next-auth/providers/credentials'

const options = {
  pages: {
    signIn: '/auth/signin',
    signOut: '/auth/signout',
    error: '/auth/error',
  },
 }

/pages/auth/error.jsx

import signin from './signin';
export default signin;

/pages/auth/signin.jsx

import React, { useState, useEffect } from 'react'
import { getCsrfToken, getProviders, useSession } from "next-auth/react"
import { useRouter } from "next/router";
import { Alert, Col, Container, Row } from 'react-bootstrap';
import { SignInForm } from './SignInForm';

export default function signin() {
  const [providers, setProviders] = useState(null);
  const [csrfToken, setCsrfToken] = useState(null);
  const router = useRouter()
  const { data: session, status } = useSession()

  useEffect(async() => {
    if (status === 'authenticated') {
      router.push('/');
    }

    if (providers === null)
      setProviders(await getProviders());
    if (csrfToken === null)
      setCsrfToken(await getCsrfToken());
    
    return () => {
      // cleanup
    }
  });

  const { query } = useRouter();

  return (
    <>
      <div className="d-flex align-items-center min-vh-100 bg-auth border-top border-top-2 border-primary">
        <Container>
          <Row className="justify-content-center">
            <Col xs={12} md={5} xl={4} className="my-5">
              {query.error && (
                <>
                  <Alert  variant="danger">
                      Could not login. Please check your e-mail or password or third-party application.
                  </Alert>
                </>
              )}
              <SignInForm providers={providers} csrfToken={csrfToken} query={query} />
            </Col>
          </Row>
        </Container>
      </div>
    </>
  )
}

/pages/auth/SignInForm.jsx

import FeatherIcon from 'feather-icons-react';
import Link from 'next/link';
import React, { useState } from 'react';

import { Card, Placeholder, Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
import { useSession, signIn, signOut } from "next-auth/react"

export default function SignInForm({...props}) {
  const { data: session, status } = useSession()

  const [showPassword, setShowPassword] = useState(false);
  const [password, setPassword] = useState("");

  function togglePassword() {
    setPassword(document.querySelector("[name='password'").value);
    setShowPassword(!showPassword);
  }

  function handleSubmit() {
    if (showPassword)
      togglePassword();
  }

  console.log(props);
  return (
    <>
    { status === 'loading' && (
      <>
        <div className="display-4 text-center mb-3">
            <Placeholder animation="glow">
              <Placeholder xs={7} /> <Placeholder xs={4} /> 
              <Placeholder xs={4} />{' '}
              <Placeholder xs={6} /> <Placeholder xs={8} />
            </Placeholder>
        </div>
      </>
    )}
    { (props.providers && props.csrfToken !== null && props.providers['credentials'] && status !== "loading") && (
      <>

        <h1 className="display-4 text-center mb-3">
        <div class="mb-3">
          <img className="navbar-brand-img" src="/img/logo-red.svg" height="70rem" alt="..." />
        </div>
          Sign in
        </h1>
        <p className="text-muted text-center mb-3">Stop checking OpenTable.</p>
        <form action={props.providers['credentials'].callbackUrl} method="post" onSubmit={handleSubmit}>
          <input type="hidden" name="csrfToken" value={props.csrfToken} />
          <div className="form-group">
            <Form.Label>Email Address</Form.Label>
            <Form.Control type="email" name="email" placeholder="name@address.com" />
          </div>
          <div className="form-group">
            <Row>
              <Col>
                <Form.Label>Password</Form.Label>
              </Col>
              <Col xs="auto">
                <Link href="/password-reset" passHref>
                  <Form.Text as="a" className="small text-muted">
                    Forgot password?
                  </Form.Text>
                </Link>
              </Col>
            </Row>
            {/* Have to use 2 input groups because it messes with Chome password mgr */}
            { showPassword && (
              <InputGroup className="input-group-merge">
                <Form.Control name="password" type="input" defaultValue={password} placeholder="Enter your password" />
                <InputGroup.Text onClick={() => togglePassword()}>
                  <FeatherIcon icon="eye" size="1em" />
                </InputGroup.Text>
              </InputGroup>
            )}
            { !showPassword && (
              <InputGroup className="input-group-merge">
                <Form.Control name="password" type="password" defaultValue={password} placeholder="Enter your password" />
                <InputGroup.Text onClick={() => togglePassword()}>
                  <FeatherIcon icon="eye" size="1em" />
                </InputGroup.Text>
              </InputGroup>
            )}
          </div>
          <Button type="submit" size="lg" className="w-100 mb-3">
            Sign in
          </Button>

        </form>
        {Object.keys(props.providers).map((providerKey, i) => (
          <>
            {
              props.providers[providerKey].type !== "credentials" && (
                <form action={props.providers[providerKey].signinUrl} method="POST">
                  <input type="hidden" name="csrfToken" value={props.csrfToken} />
                  {props.providers[providerKey].callbackUrl && (
                    <input type="hidden" name="callbackUrl" value={props.query.callbackUrl} />
                  )}

                  <Button variant="outline-secondary" type="submit" className="w-100 mb-3" size="lg">
                    Sign in with {props.providers[providerKey].name} <i className={"bi-" + props.providers[providerKey].id } role="img" aria-label="Facebook" style={ {"marginLeft": "0.5em"} }></i> 
                  </Button>
                </form>
                )
            }
          </>
        ))}
        <p className="text-center">
          <small className="text-muted text-center">
            Don't have an account yet?{' '}
            <Link href="/sign-up">
              <a>Sign up</a>
            </Link>
            .
          </small>
        </p>

      </>
    )}
    </>
  );
}

export {SignInForm};

Environment 🖥

System: Docker / macOS 10.14.6
CPU: 2.4 GHz Intel Core i9
Memory: 32GB
Shell: Docker FROM ubuntu:18.04
Binaries: Node: 14.18.0
Yarn: 1.22.17
npm: 6.14.15
Browsers: Chrome: 95.0.4638.69 (Official Build) (x86_64)
npmPackages: next-auth: 4.0.0-beta.6

Contributing 🙌🏽

Yes, I am willing to help solve this bug in a PR

@heyunoia
Copy link

heyunoia commented Nov 6, 2021

I'm having this issue too

And it's only happened when you have a custom error page

@balazsorban44
Copy link
Member

#3141 should fix this. I tested locally, but could anyone test out this release to make sure: next-auth@0.0.0-pr.3141.0a0bc030

@NuroDev
Copy link
Author

NuroDev commented Nov 7, 2021

#3141 should fix this. I tested locally, but could anyone test out this release to make sure: next-auth@0.0.0-pr.3141.0a0bc030

Just tested this release locally and seems to work / fix the issue just fine 👍🏻

@balazsorban44
Copy link
Member

Thanks! Once reviewed, it will make it into the next release.

@balazsorban44
Copy link
Member

https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-beta.7 is now released.

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

4 participants