Next Auth does not fire callback and set session hook?

I added a Credentials provider in additional to my Discord provider (which worked fine), if I try to sign up I get a success value but the session does not update Currently my nextauth file looks like this
export const authOptions: NextAuthOptions = {
session: {
strategy: 'jwt',
},
secret: 'super-secret',
jwt: {
maxAge: 15 * 24 * 30 * 60, // 15 days
},
pages: {
signIn: '/',
newUser: '/sign-up',
},
// Include user.id on session
callbacks: {
session({ session, user }) {
if (session.user) {
session.user.id = user.id
}
return session
},
jwt: async ({ token, user }) => {
if (user) {
token.id = user.id
token.email = user.email
}

return token
},
},
adapter: PrismaAdapter(prisma),
providers: [
Credentials({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'text', placeholder: 'jsmith' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
const creds = await loginSchema.parseAsync(credentials)
const user = await prisma.user.findUnique({
where: {
email: creds.email,
},
})

if (!user) {
throw new Error('User not found')
}

const isValidPassword = await verify(
creds.password,
user.password as string
)

if (!isValidPassword) {
throw new Error('Invalid password')
}

return {
id: user.id,
email: user.email,
}
},
}),
],
}

export default NextAuth(authOptions)
export const authOptions: NextAuthOptions = {
session: {
strategy: 'jwt',
},
secret: 'super-secret',
jwt: {
maxAge: 15 * 24 * 30 * 60, // 15 days
},
pages: {
signIn: '/',
newUser: '/sign-up',
},
// Include user.id on session
callbacks: {
session({ session, user }) {
if (session.user) {
session.user.id = user.id
}
return session
},
jwt: async ({ token, user }) => {
if (user) {
token.id = user.id
token.email = user.email
}

return token
},
},
adapter: PrismaAdapter(prisma),
providers: [
Credentials({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'text', placeholder: 'jsmith' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
const creds = await loginSchema.parseAsync(credentials)
const user = await prisma.user.findUnique({
where: {
email: creds.email,
},
})

if (!user) {
throw new Error('User not found')
}

const isValidPassword = await verify(
creds.password,
user.password as string
)

if (!isValidPassword) {
throw new Error('Invalid password')
}

return {
id: user.id,
email: user.email,
}
},
}),
],
}

export default NextAuth(authOptions)
This part in my frontend does not properly update after the signup process
export default function Login() {
const router = useRouter()
const { status } = useSession()
export default function Login() {
const router = useRouter()
const { status } = useSession()
status keeps being unauthorized. Not sure what I may be missing here.
29 Replies
rocawear
rocawear•3y ago
Hello, I have like this:
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
token.id = user.id;
token.email = user.email;
}

return token;
},
session({ session, token }) {
if (token && session.user) {
session.user.id = token.id as string;
}

return session;
},
}
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
token.id = user.id;
token.email = user.email;
}

return token;
},
session({ session, token }) {
if (token && session.user) {
session.user.id = token.id as string;
}

return session;
},
}
utdev
utdevOP•3y ago
@rocawear thats the only difference on your side?
rocawear
rocawear•3y ago
I think yes
utdev
utdevOP•3y ago
Buut that the same right?
rocawear
rocawear•3y ago
https://discord.com/channels/966627436387266600/1044140853041582142 here More talk about it On your example on session you are using user instead of token atleast what I noticed
utdev
utdevOP•3y ago
oh you are calling a callback url in your repo I do this
const onSubmit = useCallback(
async (data: SignUp) => {
const result = await mutateAsync(data)
console.log('result', result)
console.log('status', status)
if (result.status === 201) {
router.push('/')
}
},
[mutateAsync, router]
)
const onSubmit = useCallback(
async (data: SignUp) => {
const result = await mutateAsync(data)
console.log('result', result)
console.log('status', status)
if (result.status === 201) {
router.push('/')
}
},
[mutateAsync, router]
)
you do this
const onSubmit: SubmitHandler<ILogin> = async (data) => {
await signIn("credentials", { ...data, callbackUrl: "/dashboard" });
};
const onSubmit: SubmitHandler<ILogin> = async (data) => {
await signIn("credentials", { ...data, callbackUrl: "/dashboard" });
};
oh wait that the login sry I can try to use the token 1min nah same issue Added some logs inside my callback
callbacks: {
jwt: async ({ token, user }) => {
console.log('inside jwt callback')
if (user) {
token.id = user.id
token.email = user.email
}
return token
},
session({ session, user }) {
console.log('inside session callback')
if (session.user) {
session.user.id = user.id
}
return session
},
},
callbacks: {
jwt: async ({ token, user }) => {
console.log('inside jwt callback')
if (user) {
token.id = user.id
token.email = user.email
}
return token
},
session({ session, user }) {
console.log('inside session callback')
if (session.user) {
session.user.id = user.id
}
return session
},
},
Seems like both are not logged 🤔 after running the signup
rocawear
rocawear•3y ago
You are not using signIn?
utdev
utdevOP•3y ago
I am using signup
rocawear
rocawear•3y ago
Client API | NextAuth.js
The NextAuth.js client library makes it easy to interact with sessions from React applications.
utdev
utdevOP•3y ago
Like this:
export default function Login() {
const router = useRouter()
const { status } = useSession()

const { register, handleSubmit } = useForm<SignUp>({
resolver: zodResolver(signUpSchema),
})
const { mutateAsync } = trpc.auth.register.useMutation()

const onSubmit = async (data: SignUp) => {
const result = await mutateAsync(data)
console.log('result', result)
console.log('status', status)
if (result.status === 201) {
router.push('/')
}
}

useEffect(() => {
console.log('status', status)
if (status === AuthStates.UNAUTHENTICATED) router.push('/login')
else if (status === AuthStates.AUTHENTICATED) router.push('/dashboard')
}, [status])

return (
<AuthLayout>
<form
className="flex items-center justify-center h-auto w-full"
onSubmit={handleSubmit(onSubmit)}
>
<div className="card w-96 bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title">Create an account!</h2>
<input
type="email"
placeholder="Type your email..."
className="input input-bordered w-full max-w-xs"
{...register('email')}
/>
<input
type="password"
placeholder="Type your password..."
className="input input-bordered w-full max-w-xs my-2"
{...register('password')}
/>
<div className="card-actions items-center justify-between">
<Link href="/" className="link">
Go to login
</Link>
<button className="btn btn-secondary" type="submit">
Sign Up
</button>
</div>
</div>
</div>
</form>
</AuthLayout>
)
}
export default function Login() {
const router = useRouter()
const { status } = useSession()

const { register, handleSubmit } = useForm<SignUp>({
resolver: zodResolver(signUpSchema),
})
const { mutateAsync } = trpc.auth.register.useMutation()

const onSubmit = async (data: SignUp) => {
const result = await mutateAsync(data)
console.log('result', result)
console.log('status', status)
if (result.status === 201) {
router.push('/')
}
}

useEffect(() => {
console.log('status', status)
if (status === AuthStates.UNAUTHENTICATED) router.push('/login')
else if (status === AuthStates.AUTHENTICATED) router.push('/dashboard')
}, [status])

return (
<AuthLayout>
<form
className="flex items-center justify-center h-auto w-full"
onSubmit={handleSubmit(onSubmit)}
>
<div className="card w-96 bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title">Create an account!</h2>
<input
type="email"
placeholder="Type your email..."
className="input input-bordered w-full max-w-xs"
{...register('email')}
/>
<input
type="password"
placeholder="Type your password..."
className="input input-bordered w-full max-w-xs my-2"
{...register('password')}
/>
<div className="card-actions items-center justify-between">
<Link href="/" className="link">
Go to login
</Link>
<button className="btn btn-secondary" type="submit">
Sign Up
</button>
</div>
</div>
</div>
</form>
</AuthLayout>
)
}
rocawear
rocawear•3y ago
Yeah I think you should use signIn method Or add what signIn does by yourself
utdev
utdevOP•3y ago
So I would call register then sign in? Current register logic
register: t.procedure.input(signUpSchema).mutation(async ({ input, ctx }) => {
const { email, password } = input
const exists = await ctx.prisma.user.findUnique({
where: {
email,
},
})

if (exists) {
throw new TRPCError({
code: 'CONFLICT',
message: 'User already exists.',
})
}

const hashedPassword = await hash(password)

const result = await ctx.prisma.user.create({
data: {
email,
password: hashedPassword,
},
})

console.log('result', result)

return {
status: 201,
message: 'Account created successfully',
result: result.email,
}
}),
register: t.procedure.input(signUpSchema).mutation(async ({ input, ctx }) => {
const { email, password } = input
const exists = await ctx.prisma.user.findUnique({
where: {
email,
},
})

if (exists) {
throw new TRPCError({
code: 'CONFLICT',
message: 'User already exists.',
})
}

const hashedPassword = await hash(password)

const result = await ctx.prisma.user.create({
data: {
email,
password: hashedPassword,
},
})

console.log('result', result)

return {
status: 201,
message: 'Account created successfully',
result: result.email,
}
}),
rocawear
rocawear•3y ago
Register normally how you do but login with the signIn So when you login next auth adds some cookies (?) for you
utdev
utdevOP•3y ago
So I guess I have to do this
const onSubmit = async (data: SignUp) => {
const result = await mutateAsync(data)
if (result.status === 201) {
// call sign in from next-auth
signIn('credentials', {
email: data.email,
password: data.password,
callbackUrl: '/',
})
}
}
const onSubmit = async (data: SignUp) => {
const result = await mutateAsync(data)
if (result.status === 201) {
// call sign in from next-auth
signIn('credentials', {
email: data.email,
password: data.password,
callbackUrl: '/',
})
}
}
But not quite sure what to add to callbackUrl in this case
rocawear
rocawear•3y ago
Its where it redirects after login You dont need to mutate
utdev
utdevOP•3y ago
rocawear
rocawear•3y ago
signIn is method that handles login for you You are login not registering
utdev
utdevOP•3y ago
yeah but to login I need to first create a user I want the signup logic first before the sign in right
rocawear
rocawear•3y ago
Yes,create user normally but when login use signin
utdev
utdevOP•3y ago
yeah, I am doing the signup right now 😄 for login I am going to use signin
rocawear
rocawear•3y ago
Look my repo as example how I did register
Forsto
Forsto•3y ago
are you sure that credentials work with Prisma adapter, because in my code it didnt work with prisma
rocawear
rocawear•3y ago
Yes
rocawear
rocawear•3y ago
GitHub
t3-credentials/RegisterForm.tsx at main · ruhap/t3-credentials
t3 stack with next-auth credential provider. Contribute to ruhap/t3-credentials development by creating an account on GitHub.
GitHub
t3-credentials/auth.ts at main · ruhap/t3-credentials
t3 stack with next-auth credential provider. Contribute to ruhap/t3-credentials development by creating an account on GitHub.
utdev
utdevOP•3y ago
@rocawear if you register in your repo does it automatically update your user status?
rocawear
rocawear•3y ago
Why would it? You are creating account,not login It creates new user and redirects to login where I login with credentials
utdev
utdevOP•3y ago
ah ok, that is what I meant with first creating the user then running the signin method earlier
rocawear
rocawear•3y ago
Ok sorry,on mobile maybe I missed something
utdev
utdevOP•3y ago
ok let me try to run them seperatly give me 2 minutes 😄 signIn returns http://localhost:3000/api/auth/error?error=pchstr%20must%20contain%20a%20%24%20as%20first%20char dang
Want results from more Discord servers?
Add your server