next auth jwt session

Hello im having some problems with making the session for credentials provider i managed to make it for google provider using the Prisma adapter but since there's no adapters for the credentials i tried to make it with jwt but i don't have any idea if this is the right implementation That's the github repo : https://github.com/CLOG9/PuzChess And that's the auth code im having doubts about (from app/api/auth/[... nextauth]/options.ts):
callbacks: {
async session({ session, token, user }) {
console.log("im session", session);
session.user = token;

return session;
},
async jwt({ token, user }) {
console.log("im token", token);

return { ...token, ...user };
},
},
callbacks: {
async session({ session, token, user }) {
console.log("im session", session);
session.user = token;

return session;
},
async jwt({ token, user }) {
console.log("im token", token);

return { ...token, ...user };
},
},
GitHub
GitHub - CLOG9/PuzChess: a new chess puzzles platform made with nex...
a new chess puzzles platform made with next js. Contribute to CLOG9/PuzChess development by creating an account on GitHub.
158 Replies
barry
barry2y ago
May I ask, why JWT.
Lumberjack
LumberjackOP2y ago
Idk im new to this tbh Should i use database session instead?
barry
barry2y ago
JWT is not really recommended unless you're doing state-less auth. Like B2B, stuff where you just need to know if they're allowed or not. (B2B, Business To Business) OWASP recommends them for authentication yeah. OWASP is huge for anything application security.
Lumberjack
LumberjackOP2y ago
I couldn't find a good ressource to knw how to make database session
Lumberjack
LumberjackOP2y ago
so basically i used the database strategy, it works as excpected for the google provider but i doesn't save the session for the credentials provider, when i changed it to jwt it works fine for both except that it doesn't saving the session in db for the google provider (and thats obvious) here's the block of code
session: {
strategy: "database",
},
callbacks: {
async jwt({ token, user }) {
console.log("token user", user);
return token;
},
async session({ session, token, user }) {
if (token || user) {
session.user = token || user;
}
return session;
},
},
session: {
strategy: "database",
},
callbacks: {
async jwt({ token, user }) {
console.log("token user", user);
return token;
},
async session({ session, token, user }) {
if (token || user) {
session.user = token || user;
}
return session;
},
},
@thatbarryguy u here?
Endgame1013
Endgame10132y ago
@CLOG, I've ran into this issue before. For some reason next-auth restricts the credentials provider to only JWT (so no db sessions) unfortunately. The second paragraph on the Credentials Overview page states the following: "It comes with the constraint that users authenticated in this manner are not persisted in the database, and consequently that the Credentials provider can only be used if JSON Web Tokens are enabled for sessions."
Lumberjack
LumberjackOP2y ago
So either using jwt for both providers or just droping the credentials provider @0xahmad thats the code until now
secret: process.env.JWT_SECRET,
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user, account }) {
console.log("user", user);
console.log("account", account);
return token;
},

async session({ session, token }) {
session.user = token;

return session;
},
},
secret: process.env.JWT_SECRET,
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user, account }) {
console.log("user", user);
console.log("account", account);
return token;
},

async session({ session, token }) {
session.user = token;

return session;
},
},
when using credentials it return user undifined and the account has no token_id it works fine for the google provider
Grey
Grey2y ago
callbacks: {
jwt: async ({ token, account, user }) => {
// on login if a user is passed, we set that data to this token
user && (token.user = user);
return token;
},
session: async ({ session, token }) => {
session.user = token.user as any;
return session;
},
},
callbacks: {
jwt: async ({ token, account, user }) => {
// on login if a user is passed, we set that data to this token
user && (token.user = user);
return token;
},
session: async ({ session, token }) => {
session.user = token.user as any;
return session;
},
},
This is my set of callbacks for custom login it should return undefined, except for the time you hit signin
Lumberjack
LumberjackOP2y ago
even when i hit sign in it returns it
Grey
Grey2y ago
nah it should return it one time
Lumberjack
LumberjackOP2y ago
i'll try ur code
Grey
Grey2y ago
put console logs in there and see when it does/does not return you'll understand it's flow
Lumberjack
LumberjackOP2y ago
sure what about the sign in callback? should i use it if im using the middleware?
Grey
Grey2y ago
providers: [
CredentialsProvider({
type: "credentials",
credentials: {},
async authorize(credentials, req) {
const { username, password } = credentials as {
username: string;
password: string;
};
const user = await prisma.user.findFirst({
where: { username },
});
if (!user) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Invalid username or password",
});
}
// ... some other business logic and session management
return {
id: user.id,
name: user.username,
email: user.email ?? "",
userType: user.userType,
// ... other misc fields
};
},
}),
// ...add more providers here
],
providers: [
CredentialsProvider({
type: "credentials",
credentials: {},
async authorize(credentials, req) {
const { username, password } = credentials as {
username: string;
password: string;
};
const user = await prisma.user.findFirst({
where: { username },
});
if (!user) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Invalid username or password",
});
}
// ... some other business logic and session management
return {
id: user.id,
name: user.username,
email: user.email ?? "",
userType: user.userType,
// ... other misc fields
};
},
}),
// ...add more providers here
],
here's my provider for context yes you should use it, middleware should not interfere with your sign in process
Grey
Grey2y ago
for example here's my implementation of using the signin hook
Grey
Grey2y ago
but in this project, I hadn't needed to use any middleware, so I can't show a middleware example atm as running this project requires some prior setup
Lumberjack
LumberjackOP2y ago
thats what im having in the middleware :
export { default } from "next-auth/middleware";

export const config = {
matcher: ["/dashboard", "/play", "/leaderboard", "/profile"],
};
export { default } from "next-auth/middleware";

export const config = {
matcher: ["/dashboard", "/play", "/leaderboard", "/profile"],
};
Grey
Grey2y ago
so it's not even catching for /auth (if you have it setup under /auth like any normal setup) what is the default middleware? 🤔
Lumberjack
LumberjackOP2y ago
i don't understand purpose of the sign in callback, so i have to make it look like this
export { default } from "next-auth/middleware";

export const config = {
matcher: ["/auth/dashboard", "/auth/play", "/auth/leaderboard", "/auth/profile"],
};
export { default } from "next-auth/middleware";

export const config = {
matcher: ["/auth/dashboard", "/auth/play", "/auth/leaderboard", "/auth/profile"],
};
Grey
Grey2y ago
I've always setup a function if I wanted to use middleware, never used default ? what do you mean ? you shouldn't need any middleware for this unless next auth has changed
Lumberjack
LumberjackOP2y ago
im protecting routes
Grey
Grey2y ago
I see so then you should call default and set it up according to the docs
Lumberjack
LumberjackOP2y ago
i will change it to a function later im going to make user based role
Grey
Grey2y ago
I handled the route protecting myself so I didn't set it up that way oddly
Lumberjack
LumberjackOP2y ago
u protect it with server session?
Grey
Grey2y ago
well they setup http cookies, so I utilized my own middleware function and serverside validation, Plus I had setup a hook at the base of the page which ran with an interval and revalidated by hitting a /auth/session/verify endpoint. Logging the user out if they were not validated
Lumberjack
LumberjackOP2y ago
well to make things clear to you because im kinda lost i followed this tut : https://www.youtube.com/watch?v=w2h54xz6Ndw
Dave Gray
YouTube
Next-Auth Login Authentication Tutorial with Next.js App Directory
Web Dev Roadmap for Beginners (Free!): https://bit.ly/DaveGrayWebDevRoadmap In this Next-Auth login authentication tutorial with Next.js app directory, you will learn how to protect all of your pages with credentials or an OAuth login from providers like GitHub. Learn how to protect any page in your app. Get CodiumAI for FREE: https://mark...
Lumberjack
LumberjackOP2y ago
i see, but is my way good or should i make it like u did?
Grey
Grey2y ago
you should stick with them if you're not familiar with handling sessions properly, but it's not really a big thing to handle so if you want to you can do it on your own So to answer your question : it depends
Lumberjack
LumberjackOP2y ago
so u used HOC here?
Grey
Grey2y ago
yep
Lumberjack
LumberjackOP2y ago
and what about user based role?
Grey
Grey2y ago
here's an olderr example, which I don't recommend you do it this way, but it gets the meaning through
Grey
Grey2y ago
middleware handles it I apply patterns via next's middleware function plus my projects are literally separated by roles I have a monorepo as so: - apps - user front-end - admin front-end which are deployed to separate domains this is more extreme, yes, but the client requires it and I got the hang of doing it but for normal projects, it's just more work to handle. so I just setup a simple middleware to handle it which does like 95% of the work
Lumberjack
LumberjackOP2y ago
im having an error with the callback code u provided
[next-auth][error][SESSION_ERROR]
https://next-auth.js.org/errors#session_error Cannot read properties of undefined (reading 'user') {
message: "Cannot read properties of undefined (reading 'user')",
stack: "TypeError: Cannot read properties of undefined (reading 'user')\n" +
' at Object.session (webpack-internal:///(sc_server)/./src/app/api/auth/[...nextauth]/options.ts:41:34)\n' +
' at Object.session (webpack-internal:///(sc_server)/./node_modules/next-auth/core/routes/session.js:88:56)\n' +
' at async AuthHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/core/index.js:161:37)\n' +
' at async NextAuthRouteHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:49:30)\n' +
' at async NextAuth._args$ (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:83:24)\n' +
' at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/modu
le.js:265:37)',
name: 'TypeError'
}
[next-auth][error][SESSION_ERROR]
https://next-auth.js.org/errors#session_error Cannot read properties of undefined (reading 'user') {
message: "Cannot read properties of undefined (reading 'user')",
stack: "TypeError: Cannot read properties of undefined (reading 'user')\n" +
' at Object.session (webpack-internal:///(sc_server)/./src/app/api/auth/[...nextauth]/options.ts:41:34)\n' +
' at Object.session (webpack-internal:///(sc_server)/./node_modules/next-auth/core/routes/session.js:88:56)\n' +
' at async AuthHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/core/index.js:161:37)\n' +
' at async NextAuthRouteHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:49:30)\n' +
' at async NextAuth._args$ (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:83:24)\n' +
' at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/modu
le.js:265:37)',
name: 'TypeError'
}
Grey
Grey2y ago
how are you returning your payload from the signin handler
Lumberjack
LumberjackOP2y ago
aaaaa i remember the second option u told me about, the route protection by seperating the project
Grey
Grey2y ago
Good? well if you can do it, then it's more secure as it's decoupled and there's no chance of unauthorized admin access unless the attacker has your admin info But for the most part middlewares handle it really well also. check it properly, this should not be occuring
Lumberjack
LumberjackOP2y ago
i think im missing something, where should i find this handler?
Grey
Grey2y ago
^ this
Lumberjack
LumberjackOP2y ago
aaa the authorize method
async authorize(credentials) {
const user = await getUser(credentials?.username as string);
if (user === null) {
console.log("no user");
return null;
}
const ismatch = await bcrypt.compare(
credentials?.password,
user?.password
);
console.log(ismatch);
if (ismatch) {
console.log("logged in");

return user;
} else {
console.log("invalid pass");
return null;
}
async authorize(credentials) {
const user = await getUser(credentials?.username as string);
if (user === null) {
console.log("no user");
return null;
}
const ismatch = await bcrypt.compare(
credentials?.password,
user?.password
);
console.log(ismatch);
if (ismatch) {
console.log("logged in");

return user;
} else {
console.log("invalid pass");
return null;
}
Grey
Grey2y ago
you're returning nulls, which is raising an error that's bad practice you should raise the appropriate http errors
Lumberjack
LumberjackOP2y ago
how can i fix this?
Grey
Grey2y ago
take a look at my implementation
if (!user) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Invalid username or password",
});
}
if (!user) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Invalid username or password",
});
}
for example you should be throwing these responses
Lumberjack
LumberjackOP2y ago
wait a second, the code works fine for credentials provider but its throwing this error for the google one
Grey
Grey2y ago
*agreed this is not a trpc function, but the correct http error is still raised regardless, I just use them everywhere hmmmmmm I think then you'll have to handle it for the google provider accordingly as the jwt and session handlers catch all types
Lumberjack
LumberjackOP2y ago
also i dont see the access token in the response lemme show u first i logged the user and the token in the jwt function
user {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
token {
name: 'imadmin',
picture: null,
sub: 'clju0brhk000ruscgiba19cig',
user: {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
}
user {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
token {
name: 'imadmin',
picture: null,
sub: 'clju0brhk000ruscgiba19cig',
user: {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
}
i tried to log the session but its not triggerd so no session is created
Grey
Grey2y ago
so the user is being properly set into the token by the looks of it btw remove any unnecessary info that password hash does not belong in the token its' a major security hole anyhow, then what's the output for the google provider?
Lumberjack
LumberjackOP2y ago
yes but without the access token or the token id the error i showed ya ..
Grey
Grey2y ago
then show me the console log before setting the user in the token
Lumberjack
LumberjackOP2y ago
in the session func?
Grey
Grey2y ago
something like this:
callbacks: {
jwt: async ({ token, account, user }) => {
console.log("JayDoubleYew Kontent :: ", token, user);
// on login if a user is passed, we set that data to this token
user && (token.user = user);
return token;
},
session: async ({ session, token }) => {
console.log("Session Kontent :: ", token, user);
session.user = token.user as any;
return session;
},
},
callbacks: {
jwt: async ({ token, account, user }) => {
console.log("JayDoubleYew Kontent :: ", token, user);
// on login if a user is passed, we set that data to this token
user && (token.user = user);
return token;
},
session: async ({ session, token }) => {
console.log("Session Kontent :: ", token, user);
session.user = token.user as any;
return session;
},
},
both?
Lumberjack
LumberjackOP2y ago
sure
Grey
Grey2y ago
I forgot how google provider returns it so
Lumberjack
LumberjackOP2y ago
thats the code so u can follow the logs :
callbacks: {
jwt: async ({ token, account, user }) => {
user && (token.user = user);
console.log("user from jwt", user);
console.log("token from jwt", token);
return token;
},
session: async ({ session, token }) => {
console.log("session from session", session);
console.log("token from session", token);
session.user = token.user as any;
return session;
},
},
callbacks: {
jwt: async ({ token, account, user }) => {
user && (token.user = user);
console.log("user from jwt", user);
console.log("token from jwt", token);
return token;
},
session: async ({ session, token }) => {
console.log("session from session", session);
console.log("token from session", token);
session.user = token.user as any;
return session;
},
},
and thats the output
session from session {
user: {
name: 'Pan Caki',
image: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c'
},
expires: '2023-08-08T12:59:54.340Z'
}
[next-auth][error][SESSION_ERROR]
https://next-auth.js.org/errors#session_error Cannot read properties of undefined (reading 'user') {
message: "Cannot read properties of undefined (reading 'user')",
stack: "TypeError: Cannot read properties of undefined (reading 'user')\n" +
' at Object.session (webpack-internal:///(sc_server)/./src/app/api/auth/[...nextauth]/options.ts:42:34)\n' +
' at Object.session (webpack-internal:///(sc_server)/./node_modules/next-auth/core/routes/session.js:88:56)\n' +
' at async AuthHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/core/index.js:161:37)\n' +
' at async NextAuthRouteHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:49:30)\n' +
' at async NextAuth._args$ (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:83:24)\n' +
' at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/modu
le.js:265:37)',
name: 'TypeError'
}
token from session undefined
session from session {
user: {
name: 'Pan Caki',
image: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c'
},
expires: '2023-08-08T12:59:54.340Z'
}
[next-auth][error][SESSION_ERROR]
https://next-auth.js.org/errors#session_error Cannot read properties of undefined (reading 'user') {
message: "Cannot read properties of undefined (reading 'user')",
stack: "TypeError: Cannot read properties of undefined (reading 'user')\n" +
' at Object.session (webpack-internal:///(sc_server)/./src/app/api/auth/[...nextauth]/options.ts:42:34)\n' +
' at Object.session (webpack-internal:///(sc_server)/./node_modules/next-auth/core/routes/session.js:88:56)\n' +
' at async AuthHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/core/index.js:161:37)\n' +
' at async NextAuthRouteHandler (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:49:30)\n' +
' at async NextAuth._args$ (webpack-internal:///(sc_server)/./node_modules/next-auth/next/index.js:83:24)\n' +
' at async eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/modu
le.js:265:37)',
name: 'TypeError'
}
token from session undefined
Grey
Grey2y ago
I wanted to see the jwt one before the session one so in the jwt function put the console logs above the user && (token.user = user); sensor the unnecessary info if you want to I only want to inspect the structure, not the values AHHHH wait @CLOG I just read
Lumberjack
LumberjackOP2y ago
its not returning the jwt
Grey
Grey2y ago
callbacks: {
jwt: async ({ token, account, user }) => {
user && (token.user = user);
console.log("user from jwt", user);
console.log("token from jwt", token);
return token;
},
session: async ({ session, token }) => {
console.log("session from session", session);
console.log("token from session", token);
if (token && token.user) {
session.user = token.user as any;
}
return session;
},
},
callbacks: {
jwt: async ({ token, account, user }) => {
user && (token.user = user);
console.log("user from jwt", user);
console.log("token from jwt", token);
return token;
},
session: async ({ session, token }) => {
console.log("session from session", session);
console.log("token from session", token);
if (token && token.user) {
session.user = token.user as any;
}
return session;
},
},
here the modification is in the session function as token from session undefined is the output in the case of the google provider
Lumberjack
LumberjackOP2y ago
okay i will log the output
Grey
Grey2y ago
no need I just read the last line of this so I figured out where it's throwing
Lumberjack
LumberjackOP2y ago
the token form the session is undefined
Grey
Grey2y ago
it was throwing on the token.user and token was undefined yes as google is already handling setting the user object, you don't seem to need to do anything there for setting the user object in the session just make sure each authentication method has the same information in the user object
Lumberjack
LumberjackOP2y ago
u mean i dont need acces token and other stuff like in the credentials one?
Grey
Grey2y ago
noooooo you don't need to set any session = token.user for the google provider that's what I meant OR
if (token && token.user) {
session.user = token.user as any;
}
if (token && token.user) {
session.user = token.user as any;
}
this sufficiently handles it. Though you should double check your session data is present in the frontend after a signin to be sure
Lumberjack
LumberjackOP2y ago
i see, now in credentials its not returning the session, only the jwt with the user info so its like the oppopsite of google
Grey
Grey2y ago
for the google provider, yes
Lumberjack
LumberjackOP2y ago
what about credentials?
Grey
Grey2y ago
in the credientals? what do you mean again my logic applies for both cases
Lumberjack
LumberjackOP2y ago
its returning the jwt but no session is created
Grey
Grey2y ago
if it's google : there's no token so no session.user updates if it's credentials : then there's a token and session.user is made ?that's weird, it should be working normally how it was working a few mins ago like this
Lumberjack
LumberjackOP2y ago
it didn't work i told u but we skipped to google, i think it was missunderstanding
logged in
user from jwt {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
token from jwt {
name: 'imadmin',
picture: null,
sub: 'clju0brhk000ruscgiba19cig',
user: {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
}
logged in
user from jwt {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
token from jwt {
name: 'imadmin',
picture: null,
sub: 'clju0brhk000ruscgiba19cig',
user: {
id: 'clju0brhk000ruscgiba19cig',
role: 'BASIC',
name: 'imadmin',
password: '$2b$10$1wqZEbmOdm4omWjnjvI/8OGHf3dsbwld7haKxiKWr8jkOuCtliyRO',
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: null
}
}
Grey
Grey2y ago
this one is with which provider?
Lumberjack
LumberjackOP2y ago
credentials
Grey
Grey2y ago
and it's not setting a jwt? it should be working as it's a valid console log
Lumberjack
LumberjackOP2y ago
its returning the jwt but not the session
Grey
Grey2y ago
hmmmmmmmm you're doing something wrong with somewhere else in that case I think
Lumberjack
LumberjackOP2y ago
to make things clear, which strategy we are using here? jwt right?
Grey
Grey2y ago
if this is your setup yes then things should work properly for both as both callbacks are properly implemented
Lumberjack
LumberjackOP2y ago
so no session should be created in the db
Grey
Grey2y ago
that's upto you as in the case of jwt, it's not required. UNLESS you want to handle sessions on serverside, for the sake of invalidating them but making a session is to be done in the authorize function
Lumberjack
LumberjackOP2y ago
well pls dont curse🙂
Grey
Grey2y ago
. In this example, where I have // ... some other business logic and session management, I put my logic for it here ?
Lumberjack
LumberjackOP2y ago
i commented it by mistake
session: {
strategy: "jwt",
},
session: {
strategy: "jwt",
},
Grey
Grey2y ago
ahh
Lumberjack
LumberjackOP2y ago
now every things is woking fine
Grey
Grey2y ago
👏
Lumberjack
LumberjackOP2y ago
sessions, jwts
Grey
Grey2y ago
*slow 👏
Lumberjack
LumberjackOP2y ago
well if u dont mind
Grey
Grey2y ago
anyhow fixed now right? GGs
Lumberjack
LumberjackOP2y ago
can u explain the proccess
Grey
Grey2y ago
which one
Lumberjack
LumberjackOP2y ago
like how things should be done cuz i feel i made a spaghetty code here nd im just following without understanding how it should be done in the right way
Grey
Grey2y ago
here's the flow in the case of next auth's functions, give me a minute
Lumberjack
LumberjackOP2y ago
i think if im going touse only google i'll only setup the adapter and let it work by it self sure
Grey
Grey2y ago
export const AUTH_OPTIONS: NextAuthOptions = {
// Configure one or more authentication providers
session: { strategy: "jwt" },
jwt: {
secret: process.env.NEXTAUTH_SECRET,
maxAge: SESSION_TTL,
},
providers: [
// ...add more providers here

// INFO: The only special one is this guy, where you handle validating
// and returning the user yourself
CredentialsProvider({
type: "credentials",
credentials: {},
async authorize(credentials, req) {
// validate user
// login the user
// if you want to persist sessions in the backend, then here's the time to do it
return {
// user info which you want to store in the session
};
},
}),
],
callbacks: {
jwt: async ({ token, account, user }) => {
// here you set the user if it is present
// this user variable comes only when a signin is triggered by some provider
// this runs before the `session` function below. I put it above for that sake as well
return token;
},
session: async ({ session, token }) => {
// here you can modify the session, set anything to it
// in our usual case, we set the user to the session
// after this the session object is sent to the `jwt.encode` and then sent to the client
return session;
},
},
pages: {
signIn: "/auth/signin",
// error: '/auth/error', // Error code passed in query string as ?error=
// signOut: '/auth/signout',
},
};
export const AUTH_OPTIONS: NextAuthOptions = {
// Configure one or more authentication providers
session: { strategy: "jwt" },
jwt: {
secret: process.env.NEXTAUTH_SECRET,
maxAge: SESSION_TTL,
},
providers: [
// ...add more providers here

// INFO: The only special one is this guy, where you handle validating
// and returning the user yourself
CredentialsProvider({
type: "credentials",
credentials: {},
async authorize(credentials, req) {
// validate user
// login the user
// if you want to persist sessions in the backend, then here's the time to do it
return {
// user info which you want to store in the session
};
},
}),
],
callbacks: {
jwt: async ({ token, account, user }) => {
// here you set the user if it is present
// this user variable comes only when a signin is triggered by some provider
// this runs before the `session` function below. I put it above for that sake as well
return token;
},
session: async ({ session, token }) => {
// here you can modify the session, set anything to it
// in our usual case, we set the user to the session
// after this the session object is sent to the `jwt.encode` and then sent to the client
return session;
},
},
pages: {
signIn: "/auth/signin",
// error: '/auth/error', // Error code passed in query string as ?error=
// signOut: '/auth/signout',
},
};
here's how it works in a nutshell according to my mind and what I've read if you still don't understand, then ask specifically. Unless you want me to draw out some sort of flow diagram, which I'll do later
Lumberjack
LumberjackOP2y ago
hey i think there's a problem in the solution
Grey
Grey2y ago
?
Lumberjack
LumberjackOP2y ago
basically i have protected routes by the middleware but when i log in the middlware still require me to re-log
Grey
Grey2y ago
eh?
Lumberjack
LumberjackOP2y ago
yes
Grey
Grey2y ago
is the middleware the same/ the default and the matchers or did you put a custom one in?
Lumberjack
LumberjackOP2y ago
nope, the same matchers its just acting like your not logged in but actually u have the session in the cookies
Grey
Grey2y ago
uuhuh is it doing for both providers or just 1?
Lumberjack
LumberjackOP2y ago
both
Grey
Grey2y ago
also, it's just redirecting you to the page correct?
Lumberjack
LumberjackOP2y ago
u log in (either google, or the other guy) , redirects u to the home page (i defined the callback like that), if there is a session some new navlinks will appear in the navbar, if u click on one of them u'll get redirected to sign in page
Grey
Grey2y ago
so clicking on either of the links redirects to signin page?
Lumberjack
LumberjackOP2y ago
except the unprotected ones
Grey
Grey2y ago
and you have not setup any sort of logic in those pages per say right? Other than the middleware?
Lumberjack
LumberjackOP2y ago
no user based role, no extra layers only raw pages with the matcher
Grey
Grey2y ago
that's weird after signing in, have you verified your session is present in the cookies? and also in the db? (if you're using db auth)
Lumberjack
LumberjackOP2y ago
Lumberjack
LumberjackOP2y ago
we are using jwt
Grey
Grey2y ago
I see ok
Lumberjack
LumberjackOP2y ago
wait, im not using the sign in callback in the options there i only set the jwt nd session callbacks with you
Grey
Grey2y ago
about which part are you talking about? this error is weird as I can't pinpoint it. Send me a jwt as an example I want to inspect it's exp and iat
Lumberjack
LumberjackOP2y ago
okay i will log the jwt from jwt callback
Grey
Grey2y ago
or copy from the cookies tab easier that way
Lumberjack
LumberjackOP2y ago
{
name: 'Pan Caki',
picture: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c',
sub: 'cljvgtst3000busx86qf4t41q',
user: {
id: 'cljvgtst3000busx86qf4t41q',
role: 'BASIC',
name: 'Pan Caki',
password: null,
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c'
},
iat: 1688920422,
exp: 1691512422,
jti: '2632ccb0-5d3a-40cf-870e-39934baceeee'
}
{
name: 'Pan Caki',
picture: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c',
sub: 'cljvgtst3000busx86qf4t41q',
user: {
id: 'cljvgtst3000busx86qf4t41q',
role: 'BASIC',
name: 'Pan Caki',
password: null,
chessElo: null,
badge: 'ROCKIE',
emailVerified: null,
image: 'https://lh3.googleusercontent.com/a/AAcHTtdlF9qlq2n1_PwOrcef0LfGlB8c2Q2REca5MwrXp2x6=s96-c'
},
iat: 1688920422,
exp: 1691512422,
jti: '2632ccb0-5d3a-40cf-870e-39934baceeee'
}
Grey
Grey2y ago
no like the signed jwt or leave it
Lumberjack
LumberjackOP2y ago
the hash?
Grey
Grey2y ago
I got the iat and the exp ahhhhh your expiry is not set I figured
Lumberjack
LumberjackOP2y ago
i need to set the age ?
Grey
Grey2y ago
yes the max age
Grey
Grey2y ago
Grey
Grey2y ago
in my case the SESSION_TTL is 3600 * 6 which is 6 hours
Lumberjack
LumberjackOP2y ago
i'll check this nothing changed still blocking me
Grey
Grey2y ago
hmmmmmmmmm when you're redirected, are the cookies present? redirected to signin is what I meant
Lumberjack
LumberjackOP2y ago
yep cookies are still there
Grey
Grey2y ago
hmmmm then I honestly don't know other it being the middleware, try removing it and seeing if you see the content properly. if you do, then there's something you're missing. Check the next-auth docs in that case
Lumberjack
LumberjackOP2y ago
i'll do a final check i did this and i guess its working :
import { withAuth } from "next-auth/middleware";

export default withAuth(
async function middleware(req) {
console.log(req.nextauth.token);
},
{
callbacks: {
async authorized({ req, token }) {
if (token) return true; // If there is a token, the user is authenticated

return true;
},
},
}
);
export const config = {
matcher: ["/dashboard", "/play", "/leaderboard", "/profile"],
};
import { withAuth } from "next-auth/middleware";

export default withAuth(
async function middleware(req) {
console.log(req.nextauth.token);
},
{
callbacks: {
async authorized({ req, token }) {
if (token) return true; // If there is a token, the user is authenticated

return true;
},
},
}
);
export const config = {
matcher: ["/dashboard", "/play", "/leaderboard", "/profile"],
};
nope its not
Grey
Grey2y ago
that's because you're returning true in any case
Lumberjack
LumberjackOP2y ago
silly me
Grey
Grey2y ago
it's alright, play around with your code, and test it out. You'll find it eventually. Otherwise leave me a message, I'll check it out tomorrow 👋 or someone who's been using next-auth more than me, is more familiar with it might know and answer you
Lumberjack
LumberjackOP2y ago
sure have a great day. i guess i found the issue but i don't know how to fix it, when i log in it redirects me to the home page but in the client side its not rendering the protected links in the first render until i navigate to another page, here's the client side code :
const { data: session } = useSession();

{session?.user && (
<Link
href="/play"
className=" "
onClick={() => {
setToggle(false);
}}
>
Play
</Link>
)}
const { data: session } = useSession();

{session?.user && (
<Link
href="/play"
className=" "
onClick={() => {
setToggle(false);
}}
>
Play
</Link>
)}
i have more than that /play route.
Grey
Grey2y ago
you can use a trpc function instead of useSession to mitigate that
Lumberjack
LumberjackOP2y ago
im not using trpc in this project. is there any other solutions?
Grey
Grey2y ago
something like
getSession: publicProcedure.query(({ ctx }) => {
// INFO: THIS IS GOING TO BE REPLACED WITH A REDIS FETCH
return ctx.session;
}),
getSession: publicProcedure.query(({ ctx }) => {
// INFO: THIS IS GOING TO BE REPLACED WITH A REDIS FETCH
return ctx.session;
}),
then use getserverside props to get the session from the cookie and pass it as a prop to the page
Lumberjack
LumberjackOP2y ago
so no middleware?
Grey
Grey2y ago
oh wait it's next 13 right?
Lumberjack
LumberjackOP2y ago
yes the app dir
Grey
Grey2y ago
then you can just use the server component to get the cookie from the cookies().get() it's very easy that way, no getserverside props, I was thinking in the old pages dir style as the cookie is present, you don't have to do a specific fetch on the client side with useSession
Lumberjack
LumberjackOP2y ago
the confusion is that it was working fine before
Grey
Grey2y ago
hmm I get that, but if you can't fix it. My solution still stands as valid 🤷‍♂️ the issue you're encountering is specific to your code currently, I've never encountered it in such a way before
Lumberjack
LumberjackOP2y ago
well i can send u the repo if u don't mind where i can find that in the docs?
Lopen
Lopen2y ago
I feel you pain nextauth too just stopped working for me as expected after a while After much front and back i had to implement my own auth from scratch
Grey
Grey2y ago
I could, but I don't have enough time to gather enough context , test out the issue and help fix it. Sorry :/
Lopen
Lopen2y ago
It was more easier and straightforward
Grey
Grey2y ago
Just be sure you don't leave a gaping hole in your security. Making your own auth is easy, but also easy to shoot yourself in the foot
Lumberjack
LumberjackOP2y ago
no worries at all
Lopen
Lopen2y ago
Lol even next auth has its own gaps
Grey
Grey2y ago
for example?
Lopen
Lopen2y ago
I have forgotten by it was a topic of discussion here at some point where cj also talked a bit on it
Grey
Grey2y ago
regarding what topic about auth?
Lopen
Lopen2y ago
I can't remember
Want results from more Discord servers?
Add your server