Tralgar
Tralgar

Reputation: 290

Next auth credentials

I'm trying to do a credentials auth with next-auth. I have to use a custom sign-in page and I absolutely can't make it work for approximately one entire week.

I have :

// [...nextauth.js]

import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';

import axios from '@api/axios';

const options = {
  providers: [
    Providers.Credentials({
      async authorize(credentials) {
        const { data: user, status } = await axios.post('/users/authentication', credentials);

        if (user && status === 200) {
          return user;
        } else {
          throw new Error('error message');
        }
      }
    })
  ],
  pages: {
    signIn: '/profil/authentication/login',
    error: '/profil/authentication/login'
  },
  session: {
    jwt: true,
    maxAge: 30 * 24 * 60 * 60 // 30 days
  },
  debug: true
};

export default (req, res) => NextAuth(req, res, options);

and :

// profil/authentication/login

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

import AuthenticationForm from '@components/auth/authenticationForm';
import Layout from '@components/layout';

const Login = () => {
  const [session] = useSession();
  const intl = useIntl();

  return (
    <Layout>
      {!session && <AuthenticationForm />}
      {session && (
        <>
          Signed in as {session.user.email}
          <br />
          <button onClick={signOut}>Sign out</button>
        </>
      )}
    </Layout>
  );
};

export default Login;

// authenticationForm.js

import { signIn, csrfToken } from 'next-auth/client';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

import PasswordInput from '@components/auth/passwordInput';
import Button from '@components/form/button';
import TextInput from '@components/form/textInput';

const AuthenticationForm = ({ csrf }) => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const router = useRouter();

  const handleChangeUsername = ({ target: { value } }) => setUsername(value);

  const handleChangePassword = ({ target: { value } }) => setPassword(value);

  const handleLogin = () => {
    signIn('credentials', {
      username,
      password,
      callbackUrl: `${window.location.origin}/profil`
    })
      .then((res) => {
        console.log('form::res -> ', res);
        router.back();
      })
      .catch((e) => {
        console.log('form::e -> ', e);
        setError('login error');
      });
  };

  useEffect(() => {
    if (router.query.error) {
      setError(router.query.error);
      setUsername(router.query.username);
    }
  }, [router]);

  return (
    <form onSubmit={handleLogin}>
      <TextInput
        name="username"
        value={username}
        onChange={handleChangeUsername}
      />
      <PasswordInput handleChange={handleChangePassword} />
      {error && <div>{error}</div>}
      <Button type="submit">
      connexion
      </Button>
      <input name="csrfToken" type="hidden" defaultValue={csrf} />
    </form>
  );
};

AuthenticationForm.getInitialProps = async (context) => {
  return {
    csrf: await csrfToken(context)
  };
};

export default AuthenticationForm;

And for sure a NEXTAUTH_URL=http://localhost:3000 in .env.local.

If I go on /profil/authentication/login, I see my form and when I click connect, I always some errors like : "Failed to fetch", nothing more, or :

[next-auth][error][client_fetch_error] (2) ["/api/auth/csrf", TypeError: Failed to fetch] https://next-auth.js.org/errors#client_fetch_error

Even if I try to delete all the csrf handling in my form and let sign-in "do it alone yea".

I'm really stuck with this lib and I most likely will change for another one but I would like to know what am I doing wrong? Is there a FULL example with custom sign-in page and errors handled on the same sign-in page. This is so basic that I can't understand why I don't find one easily.

Upvotes: 6

Views: 7064

Answers (2)

Sami Ullah
Sami Ullah

Reputation: 877

I was able to fix the error by deleting the .next build folder and creating a new build by running npm run build

Upvotes: 1

Oskar
Oskar

Reputation: 116

@Tralgar

I think that problem is related to CSRF policy on your backend, if you are on localhost then localhost:3000 and localhost:2000 is like two different domains. Just make sure if you have your frontend domain in your backend cors policy (if on localhost it must be with a port)

Upvotes: 1

Related Questions