#Next auth. Please

70 messages · Page 1 of 1 (latest)

orchid flame
#

i want to get errors from next auth when user signs in with oauth

elfin lodgeBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

orchid flame
#

i spent whole 2 days for simple thing

#

i just want the method to get oauth erros on custom login page

#

i dont belive nobody needed that

#

or i think nobody builds pages by next auth

#

this not working

orchid flame
#

i give up

elfin lodgeBOT
#
✅ Success!

This question has been marked as answered! If you have any other questions, feel free to create another post

Jump to answer

[Click here](#1144343879097786569 message)

jaunty peak
orchid flame
#

there is nothing in url

#

actually

#

@jaunty peak

jaunty peak
#

Can you share your NextAuth config please?

orchid flame
#
import { prisma } from "@/lib/prisma";
import { compare } from "bcryptjs";
import type { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";
import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import { PrismaAdapter } from "@next-auth/prisma-adapter";

export const authOptions: NextAuthOptions = {
  session: {
    strategy: "jwt",
  },
  secret: process.env.NEXTAUTH_SECRET as string,
  adapter: PrismaAdapter(prisma),
  providers: [
    CredentialsProvider({
      name: "Sign in",
      credentials: {
        email: { label: "Email", type: "email", placeholder: "jsmith" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const { email, password } = credentials as {
          email: string;
          password: string;
        };
        if (!credentials || !email || !password) {
          throw new Error("Invalid credentials");
        }
        const user = await prisma.user.findUnique({
          where: {
            email: email,
          },
        });
        if (
          !user ||
          !user.password ||
          !(await compare(password, user.password))
        ) {
          throw new Error("Email or password is incorrect");
        }
       
        return {
          id: user.id,
          email: user.email,
        };
      },
    }),
    GithubProvider({
      clientId: process.env.GITHUB_ID as string,
      clientSecret: process.env.GITHUB_SECRET as string,
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    }),
  ],

  pages: {
    signIn: "/login",
    error: "/login",
    signOut: "/login",
  },
};```
#
import Link from "next/link";
import LoginForm from "./form";
import { redirectIfAuthenticated, signOutIfBlocked } from "@/lib/protected";

export default async function Login({
  params: { lang },
}: {
  params: { lang: string };
}) {
  await redirectIfAuthenticated();
  // get query error
  return (
    <div>
      <div className="p-5 flex flex-col gap-3 items-start">
        <h2 className="font-bold text-2xl">Welcome back!</h2>
        <p className="text-tsecondary">
          {"Don't have an account? "}
          <Link className="underline" href="/register">
            Create an account
          </Link>
        </p>
        <LoginForm />
      </div>
    </div>
  );
}
#

next/router doesnt work in new nextjs

jaunty peak
#

Yeah, use next/navigation instead

orchid flame
#

but there is no error in next/navigation query

#

or in useSearchParams

jaunty peak
#

Because there is no error in your URL

#

We gotta find out why

orchid flame
#

because when you sign in google

#

its redirected to google page then from google page

#

redirected to some link like /api/auth/providers/google

#

i dont remember

jaunty peak
#

That's fine so far

#

It gets a token from Google, then uses that token to get the user data in the callback

orchid flame
#

i dont understand why signIn function doesnt have error handler itself

#

yes ans as we see in network page it actually gets this error in url

jaunty peak
#

Yup

#

Let me test some stuff

orchid flame
#

okay

jaunty peak
#

What does await redirectIfAuthenticated(); do?

orchid flame
#
export async function redirectIfAuthenticated() {
  const session = await getServerSession(authOptions);
  session && redirect("/");
}```
jaunty peak
#

Can you comment that line out and test?

#

Because something is redirecting you

#

And that is why you are not getting passed the URL parameters

orchid flame
#

yes and its same

orchid flame
#
"use client";
import { AiOutlineLoading3Quarters } from "react-icons/ai";
import React, { useState } from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import { signIn } from "next-auth/react";
import {
  useParams,
  usePathname,
  useRouter,
  useSearchParams,
} from "next/navigation";
import { FaGithub, FaGoogle } from "react-icons/fa";
const CALLBACK_URL = "/";

const LoginForm = () => {
  const [error, setError] = useState<null | string>(null);
  const [loading, setLoading] = useState(false);
  const router = useRouter();

  const validateForm = (values: { email: string; password: string }) => {
    const errors: any = {};
    if (!values.email) {
      errors.email = "Required";
    } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
      errors.email = "Invalid email address";
    }
    if (!values.password) {
      errors.password = "Required";
    }
    return errors;
  };

  const handleSubmit = (
    values: {
      email: string;
      password: string;
    },
    { setSubmitting }: any
  ) => {
    setLoading(true);
    setError(null);
    const { email, password } = values;
    signIn("credentials", {
      redirect: false,
      email,
      password,
    })
      .then((res) => {
        router.push(CALLBACK_URL);
      })
      .catch((err) => {
        setSubmitting(false);
        setLoading(false);
        setError(err.message);
      });
  };
#
return (
    <>
      {error && <div className="text-red-500">{error}</div>}
      <Formik
        initialValues={{ email: "", password: "" }}
        validate={validateForm}
        onSubmit={handleSubmit}
      >
        {({ isSubmitting }) => (
          <Form className="flex flex-col gap-3 items-start max-w-xs w-full">
            <Field
              className="border border-secondary p-3 bg-transparent outline-none w-full rounded-sm"
              placeholder="Please enter your email..."
              type="email"
              name="email"
            />
            <ErrorMessage name="email" component="div" />
            <Field
              className="border border-secondary p-3 bg-transparent outline-none w-full rounded-sm"
              placeholder="Please enter your password..."
              type="password"
              name="password"
            />
            <ErrorMessage name="password" component="div" />
            <button type="submit" disabled={isSubmitting}>
              {loading ? (
                <AiOutlineLoading3Quarters className="animate-spin text-2xl" />
              ) : (
                "Sign In"
              )}
            </button>
          </Form>
        )}
      </Formik>
      {/* or sign in with google or github */}
      <button
        type="button"
        onClick={() => {
          signIn("google", {
            redirect: false,
          });
        }}
  
      >
        <FaGoogle />
        google
      </button>
      <button
        type="button"
        onClick={() => {
          signIn("github", {
            redirect: false,
          });
        }}
     
      >
        <FaGithub />
        github
      </button>
    </>
  );
};

export default LoginForm;
jaunty peak
#

Ik

#

And you can see in the response headers that it redirects you without parameters

#

So seems the be the localization

#

Can you show me how that's implemented?

orchid flame
#
import { NextRequest, NextResponse } from "next/server";
import { match } from "@formatjs/intl-localematcher";
import Negotiator from "negotiator";
import { defaultLocale, locales } from "./locals";

function getLocale(request: NextRequest) {
  const headers = new Headers(request.headers);
  const acceptLanguage = headers.get("accept-language");
  if (acceptLanguage) {
    headers.set("accept-language", acceptLanguage.replaceAll("_", "-"));
  }
  const headersObject = Object.fromEntries(headers.entries());
  const languages = new Negotiator({
    headers: headersObject,
  }).languages();
  return match(languages, locales, defaultLocale);
}

export function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname;
  const pathnameIsMissingLocale = locales.every(
    (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
  );
  if (pathnameIsMissingLocale) {
    const locale = getLocale(request);
    return NextResponse.redirect(
      new URL(`/${locale}/${pathname}`, request.url)
    );
  }
}

export const config = {
  matcher: ["/((?!_next|api|favicon.ico).*)"],
};
jaunty peak
#

Alright, one sec

orchid flame
#

why is there

#

two /

#

i removed api from matcher

#

and now there is 404 page

jaunty peak
# orchid flame ```js import { NextRequest, NextResponse } from "next/server"; import { match } ...

So the issue is that pathname does not include URL parameters. So when redirecting the user to their locale, your middleware dumps all query parameters.
To fix this, make the following changes in your middleware function:

// add this line where you also define your `pathname` variable:
const searchParams = request.nextUrl.search;
// edit your redirect line like this:
return NextResponse.redirect(
  new URL(`/${locale + pathname + searchParams}`, request.url);
);
#

Here's a screenshot of the structure of the request.nextUrl object to better understand why this error occurred and how we fix it

orchid flame
#

yes i understand

#

thanks

elfin lodgeBOT
#
✅ Success!

This question has been marked as answered! If you have any other questions, feel free to create another post

Jump to answer

[Click here](#1144343879097786569 message)

jaunty peak
orchid flame
#

okay

#

and i have one question if you have time

#
const errors = {
  Signin: "Try signing with a different account.",
  OAuthSignin: "Try signing with a different account.",
  OAuthCallback: "Try signing with a different account.",
  OAuthCreateAccount: "Try signing with a different account.",
  EmailCreateAccount: "Try signing with a different account.",
  Callback: "Try signing with a different account.",
  OAuthAccountNotLinked:
    "To confirm your identity, sign in with the same account you used originally.",
  EmailSignin: "Check your email address.",
  CredentialsSignin:
    "Sign in failed. Check the details you provided are correct.",
  default: "Unable to sign in.",
};
const SignInError = ({ error }: any) => {
  const errorMessage =
    error && (errors[error as keyof typeof errors] ?? errors.default);
  return <div className="text-red-500">{errorMessage}</div>;
};```
#

is this right way?

jaunty peak
#

It's not a wrong way so you should be fine using this

orchid flame
#

okay thanks

#

it would be good if signIn function itself had error handling functionallity

#

like credentials signIn works

#

thanks a lot