I'm using next-auth/discord however when using the session callback to set a user id to the session it does not set the property.
[...nextauth].js
import NextAuth from "next-auth/next";
import DiscordProvider from "next-auth/providers/discord";
export default NextAuth({
providers: [
DiscordProvider({
...
session: {
strategy: "jwt",
...
},
callbacks: {
async session({ session, user }) {
session.user.id = user.id;
return session;
}
}
})
]
});
/api/page.js
import { getSession } from 'next-auth/react';
export default async function handler(req, res) {
const session = await getSession({ req });
console.log(session);
}
This logs:
{
user: {
name: ...,
email: ...,
image: ...
},
expires: ...
}
With no user.id property.
Fixed it, callbacks should have been in NextAuth object. Also callbacks shouldve been:
async jwt({ token, user }) {
if (user) {
token.id = user.id
}
return token
},
async session({ session, token }) {
session.user.id = token.id
return session
}
Related
I am trying to learn next-auth, I finally got the login to work but when I pass the id from the user in the database it doesn't show up in the session only the values that I provided null to show up
import NextAuth from 'next-auth'
import CredentialProvider from 'next-auth/providers/credentials'
import connectMongo from '../../../lib/db'
import User from '../../../models/userModel'
export const authOptions = {
session: {
strategy: 'jwt',
},
providers: [
CredentialProvider({
async authorize(credentials) {
await connectMongo()
const u = await User.findOne({ username: credentials.username })
console.log(u.id)
if (u) {
return {
id: u.id,
name: null,
email: null,
image: null,
}
}
// login failed
return null
},
}),
],
}
export default NextAuth(authOptions)
login is successful with no errors but the id doesn't show up in the props.
{email: null, image: null, name: null} is all that is returned.
If I don't add null to all those keys it returns this error SerializableError: Error serializing .session.user.name returned from getServerSideProps in "/authenticated".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
import { authOptions } from './api/auth/[...nextauth]'
import { unstable_getServerSession } from 'next-auth/next'
function Authenticated(props) {
return <div>Authenticated</div>
}
export default Authenticated
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
if (!session) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
return {
props: {
session,
},
}
}
get session in getServerSideProps also returns an empty object after successful login with no errors
import { getSession } from 'next-auth/react'
function Authenticated(props) {
console.log(props)
return <div>Authenticated</div>
}
export default Authenticated
export async function getServerSideProps(context) {
const session = await getSession({ req: context.req })
if (!session) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
return {
props: { session },
}
}
I want to render data in client side below from parse after signin from next auth using useSession
{
objectId: 'nttMcKIOQJ',
username: 'fiik346',
email: 'fiik346#gmail.com',
createdAt: '2022-06-26T07:56:41.888Z',
updatedAt: '2022-06-26T07:56:41.888Z',
ACL: { '*': { read: true }, nttMcKIOQJ: { read: true, write: true } },
sessionToken: 'r:2f2c569be3b5120f3893834c2ace7b67'
}
But it's just render email
{"user": {"email":"fiik346#gmail.com"},"expires":"2022-07-26T09:01:41.163Z"}
"authenticated"
This is my callbacks code
// /pages/api/auth/[...nextauth].js
...
callbacks: {
async session({ session, token, user }) { // Send properties to the client, like an access_token from a provider. return session
}, async jwt({ token, user, account, profile, isNewUser }) { return token
} },
...
And client side code
import { useSession } from 'next-auth/react'
import { getToken } from 'next-auth/jwt'
export default function accountIndex() {
const {data: session, status} = useSession() return ( <div>
<h1>Account is {status}</h1>
<pre className="overflow-auto">
{JSON.stringify(session)}
<br/>
{JSON.stringify(status)}
</pre>
</div>
)
}
I don't know how to change my callbacks code to display data from database
callbacks: {
jwt: async ({token, user}) => {
if (user) {
token.data = user
}
return token
},
session: async ({session, token}) => {
if (token.data) {
session.user = token.data
}
return session
}
}
After a while and try harder, I was successful to render data. Just change callback code like below.
...
callbacks: {
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.
session.accessToken = token.accessToken
session.user = token.data
return session
},
async jwt({ token, user, account, profile, isNewUser }) {
if (user) {
token.data = user
}
return token
}
},
...
Having some trouble with setting up nextauth v4. Getting this error:
Client fetch error, Unexpected end of JSON input {error: {…}, path:
'session', message: 'JSON.parse: unexpected end of data at line 1
column 1 of the JSON data'}.
To fix it they say you have to add the url path to a .env file when deploying. I’m working on localhost so this shouldn't be a problem, but after adding it, still the same error.
When I comment out the async session callback in [...nextauth] file, the error doesn’t pop up and the session is “authenticated” but doesn’t persist. I’ve been staring it at this for a good while now and could use some help!
[...nextauth].js
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { PrismaClient } from "#prisma/client";
const prisma = new PrismaClient();
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials, res) {
//find existing user
const user = await prisma.user.findUnique({
where: {
email: credentials.email,
},
});
if (
credentials.email === user.email &&
credentials.password === user.password
) {
return user;
} else {
return res.status(409).send({ message: "No user with that email." });
}
},
}),
],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
return token;
}
},
//commenting this function and no error shows up
async session({ session, token }) {
if (token) {
session.id = token.id;
return session;
}
},
},
secret: "mysecret",
jwt: {
secret: "mysecret",
encryption: true,
},
session: {
strategy: "jwt",
maxAge: 1 * 24 * 60 * 60,
},
});
auth-form
import { signIn, useSession } from "next-auth/react";
export default function AuthForm() {
const { data: session } = useSession();
const handleSubmit = async (userData) => {
const { error, ok, url } = await signIn("credentials", {
redirect: false,
email: userData.email,
password: userData.password,
callbackUrl: "/profiel",
});
if (ok) {
router.push(url);
} else {
alert(error);
}
};
return (
<Form onSubmit={handleSubmit}>
<Field id="email" />
<Field id="password" />
<button type="submit">{isRegistered ? "Sign in" : "Register"}</button>
</Form>
);
}
_app.js
import { SessionProvider } from "next-auth/react";
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}
The session and jwt callbacks need to return a session and jwt object respectively. You need to move the return statements in each function after the if block.
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
}
return token;
},
async session({ session, token }) {
if (token) {
session.id = token.id;
}
return session;
}
}
I am using Next-Auth Credentials provider to authenticate using our existing API.
When I follow the directions on https://next-auth.js.org/configuration/callbacks
like this:
callbacks: {
async jwt({ token, user }) {
if (user) {
token.accessToken = user.jwt
}
return token
},
async session({ session, token, user }) {
session.accessToken = token.accessToken
return session
}
}
the resulting session object from useSession() looks like this:
{
expires: "2022-03-22T18:29:02.799Z",
user: {email: 'john#nextIsGreat.com'}
}
I can't use that as it does not have the token available.
So I was able to make up my own working solution, but it is kind of strange because of the way things are grouped together. Here is what I am doing now, that I am trying to figure out how to do better. I use comments to point out the problem areas:
[...nextauth].js:
import NextAuth from 'next-auth'
import Credentials from 'next-auth/providers/credentials'
import axios from 'axios'
export default NextAuth({
providers: [
Credentials({
name: 'Email and Password',
credentials: {
username: { label: 'Username', type: 'text', placeholder: 'jsmith' },
password: { label: 'Password', type: 'password' }
},
authorize: async (credentials) => {
const url = process.env.API_URL + '/authenticate'
const result = await axios.post(url, {
username: credentials.username,
password: credentials.password
})
const user = result.data
console.log(user)
//It logs this:
/*
{
jwt: 'eyJhbasU1OTJ9.NQ356H4Odya62KmN...', //<---***This is the token i pass in to all of my API calls****
user: {
userId: 207,
email: 'john#nextIsGreat.com',
firstName: 'John',
lastName: 'Doe',
roleId: 1,
}
}
*/
if (user) {
return Promise.resolve(user)
} else {
return Promise.resolve(null)
}
}
})
],
callbacks: {
async jwt({ token, user }) {
if (user) {
if (user.jwt) {
token = { accessToken: user.jwt, restOfUser: user.user }
}
}
return token
},
async session(seshProps) {
return seshProps
}
}
})
Home.js:
export const Home = () => {
const { data: session } = useSession()
console.log(session)
//LOGS THIS --->
/*
{
"session": { "user":{}, "expires":"2022-03-22T17:06:26.937Z"},
"token":{
"accessToken":"eyJ...",
"iat":1645376785,
"exp":1647968785,
"jti":"41636a35-7b9a-42fd-8ded-d3dfgh123455a"
"restOfUser": {
"userId":207,
"email":"john#nextIsGreat.com",
"firstName":"John",
"lastName":"Doe",
"roleId":1
}
}
{
*/
const getPosts=()=> {
const url = 'localhost:4000/posts'
const {data} = axios.get(url, {
Authorization: session.token.accessToken <--**This is the way I am calling my API
})
console.log(data)
}
return (
<div onClick={getPosts}>
Hello, {session.token.restOfUser.firstName}
/* I have to access it like this now, which seems wrong ***** */
</div>
)
}
Cheers for creating your own solution but you do not need it. NextAuth CredentialsProvider handles it already by setting your NextAuth session configuration to session: {strategy: "jwt", ... }.
You can also remove your callbacks for jwt() and session() and remove your owned generated JWT access token. As you do not need it, this way you can authenticate your existing system.
And at your CredentialsProvider({authorize(){}} authorize method. If you had directly connected to the user database, you can directly look up the user credential without doing a post request since it is already considered a server-side function.
I've working in a project with Next.js (11.1.2) + NextAuth (^4.0.5) + Strapi(3.6.8).
I'm using Next Auth credentials provider and it's working fine. But I need to access a few user information using session, so I tried to do this using jwt and session callbacks.
When I log response from strapi inside authorize(), I receive { jwt:{}, user:{} }, so it's ok.
//[...nextauth.js]
async authorize(credentials, req) {
try {
const { data } = await axios.post(process.env.CREDENTIALS_AUTH_URL, credentials)
if (data) {
//console.log('data: ', data) //this is ok
return data;
}
else {
return null;
}
} catch (e) {
return null;
}
},
But, in jwt callback, when I log token, i'm getting a bizarre obj with {token:{token:{token:{...}}}:
// [...nextauth.js] callback:{ jwt: async (token) => { console.log(token) }}
token: {
token: {
token: {},
user: {
jwt: ...,
user: [Object]
},
account: { type: 'credentials', provider: 'credentials' },
isNewUser: false,
iat: ...,
exp: ...,
jti: ...
}
}
And account and user is always undefined inside that callbacks.
Finally, when I get session from useSession in a page, I get this:
// console.log(session) in any page
{
session: {
expires: "2022-01-12T19:27:53.429Z"
user: {} // empty
},
token:{
token:{
account: {type: 'credentials', provider: 'credentials'}
exp: ...
iat: ...
isNewUser: false
jti: "..."
token: {} // empty
user: { //exactly strapi response
jwt:{...}
user:{...}
}
}
}
}
All examples I've found aren't handling this objects with this confuse structure and I don't know if I missing something out. Can you help me?
This is my [...nextauth].js:
import NextAuth from "next-auth"
import CredentialsProvider from 'next-auth/providers/credentials'
import axios from 'axios';
export default NextAuth({
providers: [
CredentialsProvider({
name: '...',
credentials: {
email: {label: "Email", type: "text", placeholder: "email#provider.com"},
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
try {
const { data } = await axios.post(process.env.CREDENTIALS_AUTH_URL, credentials)
if (data) {
//console.log('data: ', data)
return data;
}
else {
return null;
}
} catch (e) {
return null;
}
},
})
],
secret: process.env.SECRET,
session: {
strategy: 'jwt',
maxAge: 30 * 24 * 60 * 60 // 30 days
},
jwt: {
secret: process.env.JWT_SECRET,
encryption: true,
},
callbacks: {
jwt: async (token, account) => {
console.log('### JWT CALLBACK ###')
console.log('token: ', token)
console.log('account: ', account)
return token;
},
session: async (session, token, user) => {
console.log('### SESSION CALLBACK ###')
console.log('session: ', session)
console.log('user: ', token)
console.log('user: ', user)
return session;
}
},
pages: {
signIn: '/signin',
signOut: '/signin',
error: '/signin'
}
})
try pls:
- session(session, tokenOrUser)
+ session({ session, token, user })
- jwt(token, user, account, OAuthProfile, isNewUser)
+ jwt({ token, user, account, profile, isNewUser })
https://next-auth.js.org/getting-started/upgrade-v4#callbacks