Next.js Discord

Discord Forum

issue about auth

Unanswered
Golden northern bumble bee posted this in #help-forum
Open in Discord
Golden northern bumble beeOP
i don't see any explanation on how to use jwt with nextauth, i don't want any auth providers just username password auth but with jwt.

246 Replies

Golden northern bumble beeOP
and should i use nextauth, if so why?
@Golden northern bumble bee and should i use nextauth, if so why?
American Chinchilla
Next auth isnt recommended
For email password
It says so on their doc
Also Next auth is hard to configure JWT , there are guides out there but its not clean
If scroll down to JWT you will a guide there on how to set it up
For username and password, I will say you are going to have to them enter email anyway for security purposes like password reset etc
For that kind of stuff you could use Clerk which is popular but might be paid or use Firebase
Im personally using passport.jw which i find great too but it only supported on Node js
Golden northern bumble beeOP
I don't want password resets right now
I just want the auth process done
American Chinchilla
Yeah then Clerk can be your choice
Its really easy to use
Its support next.js
@Golden northern bumble bee I just want the auth process done
Brown bear
You can also make your own auth system
@Brown bear You can also make your own auth system
Golden northern bumble beeOP
with jwt?
Brown bear
Yeah
I do that
Golden northern bumble beeOP
I know thats what I was intented to do
save RT and access to the RT with an access token
that's probably what I'll do
Brown bear
You don't need next auth then
Golden northern bumble beeOP
yes 👍🏻
also another question where do you think i should save the access token
in cookies or in local storage?
Brown bear
Cookies
And make them http only
Golden northern bumble beeOP
o
Brown bear
For safety reasons
@Golden northern bumble bee I know thats what I was intented to do
Golden northern bumble beeOP
this system has no exploits right?
Brown bear
Jwt if implemented correctly is very safe
Golden northern bumble beeOP
oo
aight
also my permission system is gonna be bitwise too
Brown bear
Just remember
Jwt tokens should have a man age of 2hours and refresh tokens should be stored in http only cookies
Golden northern bumble beeOP
this project is gonna be very detailed, secure, and professional
Brown bear
Jet is a great way to do perms
And handle perms
Golden northern bumble beeOP
jet?
Brown bear
Jwt*
Golden northern bumble beeOP
I'll store the username in jwt token
and send a request to the backend checking the permission level of the user
and then compare with bitwise operators
Brown bear
Why do that instead you can store users permissions on the jwt
Golden northern bumble beeOP
JWT can be altered afaik
Brown bear
No
If it's altered it won't work
Golden northern bumble beeOP
i want it to be as safe as possible
Brown bear
You cant alter jwts and have them work
Golden northern bumble beeOP
work as in jwt.verify()?
i already set up my database and shit
for the system i told
Brown bear
Learn more about jwts and how to implement them they're very safe
@Brown bear Learn more about jwts and how to implement them they're very safe
Golden northern bumble beeOP
how would u do it?
would u just put the permission integer in the jwt?
Brown bear
Yes
@Brown bear Learn more about jwts and how to implement them they're very safe
American Chinchilla
Sorry, although I do like JWT i will have to say that is not true
Even if using blacklist to invalidate tokens, any session or database saving with jwt is basically recreating sessions which is not any more securer since it hasnt been tested compared to sessions.
Its more better to use sessions than JWT
But this doesnt mean you cant use JWT, as it depends on your use case and with best security practices you make JWT more properly secured but it still wont be any more securer than sessions.
theyre very safe
the jwt token would have a life span of from 15m to an hour after they expire you would use your refresh token which is stored in http only cookies to get jwt token the refresh token can easily be revoked too if user chooses to log out or change password
Golden northern bumble beeOP
hey @Brown bear are you awake?
Golden northern bumble beeOP
would this be secure enough?
Brown bear
A user logs in
A refresh token is fetched or gets generated by or from DB api returns that refresh token as http only cookie after yiu send another request with that refresh token to get your jwt token
American Chinchilla
Its not secure to refresh tokens in a DB
And is basically a session but less secure
And also JWT tokens cant be revoked
Its a part of JWT mechanism
Yes they may be removed from cookie but theyre still valid
Expiry date does help to a degree but it’s difficult when user sign outs
Because you cant invalidate tokens
You can only either store a blacklist to keep track of invalid tokens in a DB etc
If the database gets a breach
The hacker can now use the JWT token to impersonate a user
A safety measure would be to use csrf Tokens which is maybe out of the scope for this
Owasp guidelines which is the standard for auth even mentions this all that i said above
The better approach for JWT is to store a blacklist of tokens between the expiry date and logout
And using a hashed Csrf token in a session like redis or a database
This way even if the DB gets breached , there no way to impersonate the user
And also the hacker wont be able to do cross site login because of the csrf token
@American Chinchilla This way even if the DB gets breached , there no way to impersonate the user
Golden northern bumble beeOP
this won't be able to do anyways
@Golden northern bumble bee this won't be able to do anyways
American Chinchilla
May i ask what do you mean?
Golden northern bumble beeOP
in my system you wont be able to impersonate the user
@American Chinchilla The hacker can now use the JWT token to impersonate a user
Brown bear
if the database gets breached my last concern is someone impersonating a user
and refresh tokens can be easily revoked so theyd have 15 minutes of impersonating that user at most
@American Chinchilla You can only either store a blacklist to keep track of invalid tokens in a DB etc
Brown bear
jwt tokens are never ment to be stored in db
yes they cant be revoked
but they last for 15 minutes
the way you get them which is refresh tokens can be revoked
and is stored in db
@Golden northern bumble bee but dude if i hash a refresh token i can't unhash it
Brown bear
why would you unhash them ?
@Brown bear why would you unhash them ?
Golden northern bumble beeOP
unhash, verify the token
no?
Brown bear
no
Golden northern bumble beeOP
how else
Brown bear
after the user logs in you will set it in there http only cookie
adn it will be sent with every request they send to you
Golden northern bumble beeOP
i hash the refresh token
and store it in the db
Brown bear
yes and set it in the clients settings
Golden northern bumble beeOP
!???
clients settings what?
Brown bear
cookies
Golden northern bumble beeOP
yea im not at that part yet im making the /refresh route to refresh the JWT token
access token
using the refresh tokrn
basically
I've done the register route
when a user registers
since its an invite only service
take the credentials > check for duplicate user if passed > check for the invite if exists > check if invite is used if not > generate 2 jwts an access token and a refresh token send both back, hash and save the refresh token in DB too
when a user hits /refresh route he sends username and refresh token from browser and if the refresh token is valid it generates a new access token for him
isn't this how it should work
Brown bear
he shouldnt send his user name
the refresh token should contain his id
so he cant change it
and also refresh token should have a one to many relation with user
a user can have many refresh tokens
Golden northern bumble beeOP
why would
u can just remove when the RT is expired
u don't need 500000 refresh tokens
Brown bear
no
cause the refresh token also has a device id
wait ill show you
Golden northern bumble beeOP
I am not doing a device id checker its a basic kindergarten site my guy
Brown bear
its really easy
just make a unique uuid in the cookies thats called a device id
Golden northern bumble beeOP
h e l l n o
i don't see a purpose on that it's only a kindergarten site
Brown bear
but what if they have more than one device
they login on there phone
the old refresh token gets updated
and now when they check the website on there pc
they need to login again
because they have an invalid refresh token
here
ill give you the code to add device id
its piss easy
import Cookies from 'js-cookie';
import { generateUUID } from './uuid';

export function getOrSetDeviceIdentifier() {
if (typeof window !== 'undefined') {
let deviceIdentifier = Cookies.get('deviceIdentifier');

if (!deviceIdentifier) {
deviceIdentifier = generateUUID();
Cookies.set('deviceIdentifier', deviceIdentifier, { expires: 365, sameSite: 'Secure' });
}

return deviceIdentifier;
}

}



export function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
thats it
generate a UUID and save it in cookies
CREATE TABLE public.tbl_ams_usertoken (
tokenid varchar(255) NOT NULL,
userid int4 NOT NULL,
deviceid varchar(255) NOT NULL,
creationdate timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
expirationdate timestamp DEFAULT (CURRENT_TIMESTAMP + '30 days'::interval) NOT NULL,
isactive bool DEFAULT true NOT NULL,
CONSTRAINT pk_tbl_usertoken PRIMARY KEY (tokenid),
CONSTRAINT fk_tbl_usertoken_tbl_users FOREIGN KEY (userid) REFERENCES public.tbl_ams_users(userid)
);

here is what your token schema should look like
Golden northern bumble beeOP
dude
the token is inside user table
it's a fueld
i don't wanna do that
i wanna finish the registration etc
Brown bear
Bruh
Just go with session authentication then
Even with session authentication you need the session to be a separate table
What you can do is make another table called session
Link it eith the user the session should have a session token user I'd and his permission level and a creation date and an expired date
Golden northern bumble beeOP
man why
Brown bear
You set that session ID as an http only cookie and every time he sends you a request you need to verify of this user is who he is
Golden northern bumble beeOP
what do you need a refresh token table for
Brown bear
There are 2 ways of authentication
Session and jwt
Golden northern bumble beeOP
wtf is a session id bro
Brown bear
Both require a separate table from the user
Golden northern bumble beeOP
what is the reason
LMAO
its complete useless
Brown bear
I'll explain in a call bruh oam sick of typing
Golden northern bumble beeOP
send a voice note in dms
Brown bear
So you want a secure authentication system with permissions ?
Golden northern bumble beeOP
yes
Brown bear
You think you can make it without another table ? Only a field in the users table ?
Golden northern bumble beeOP
yes
Brown bear
Okay try
The best way to understand why is trying and learning
Golden northern bumble beeOP
how do i unhash something
Brown bear
You mean the jwt token ?
Golden northern bumble beeOP
yes
i hashed it with argon2
Brown bear
You decod it
Hashes aren't ment to be unhashed
Hashing is a one way function
You use a library to create then
Them
And that library has a decode function that gets the data out
Golden northern bumble beeOP
brother
@Brown bear Hashes aren't ment to be unhashed
Golden northern bumble beeOP
how do i check if the refresh token JWT is valid then
Golden northern bumble beeOP
ya allah
Brown bear
You use a library to create verify and decode the tokens
Golden northern bumble beeOP
I am going to commit unspeakable acts
AY DON'T DAY THAT BRUH
DELETE AND MOVE TO DMS IF U WANNA TALK LIKE THIS
Brown bear
You cant just create tokens with your shitty ass alg
There are libraries for it
That you need to use
Watch the video
You haven't even generated one correctly
If it's too complex
Use a 3rd party service
Golden northern bumble beeOP
generated what
WHAT
wyftb
@Brown bear the way you get them which is refresh tokens can be revoked
American Chinchilla
Im a bit confused
Isnt that what i just said?
Also by refresh tokens , you mean also acess and refresh tokens?
Typically access tokens are the 15min short lived
While refresh are longer like a few days etc
@Golden northern bumble bee but dude if i hash a refresh token i can't unhash it
American Chinchilla
Not sure why you are hashing refresh token
Its redudant
@Golden northern bumble bee how do i unhash something
American Chinchilla
You can not unhash
Hash is one way
I think you mean encryption which can be unencrypted
@American Chinchilla Not sure why you are hashing refresh token
Golden northern bumble beeOP
American Chinchilla
Yeah dont believe every site.
He already doing bad practices
If you check owasp they mention the best practies
And solutions for jwt token “invoked”
He mentioned about storing tokens via local storage
Which isnt secure
Its even warned in owasp guidelines
Also its a self publishes article
No where does he even backup his claims
Your better off looking at freecodecamp articles
And even in those article they talk about black listing tokens
Its up to you how you want to do things, i just mentioned the best security practices according to the official owasp guidelines, and from what I learned from other professionals developers in Reactiflux discord server.
@Brown bear You cant just create tokens with your shitty ass alg
American Chinchilla
Please dont be rude, this is a community server to help, you can disagree but please be respectful
i allow it
@Brown bear yo
what kinda data should i keep
in refresh_token
Golden northern bumble beeOP
export const refresh_tokens = pgTable("refresh_tokens", {
    id: serial('id').notNull(),
    user_id: integer().notNull(),
    username: varchar().notNull(),
    refresh_token: varchar('refresh_token').notNull().primaryKey(),
    ip_adress: varchar(),
    revoked: boolean().default(false).notNull(),
    expires_at: timestamp().notNull(),
    issued_at: timestamp().notNull().defaultNow()
});
is this good enough
Golden northern bumble beeOP
import { db } from "@/lib/db";
import { refresh_tokens, users } from "@/lib/schema";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import * as jwt from "jsonwebtoken";

const JWT_RT_SECRET = process.env.JWT_RT_SECRET as string;

export async function POST(req: Request) {
  const body = await req.json();
  const { refresh_token } = body;

  if (!refresh_token) {
    return NextResponse.json({ error: "Refresh token is required" }, { status: 400 });
  }

  let decoded;
  try {
    decoded = jwt.verify(refresh_token, JWT_RT_SECRET);
  } catch {
    return NextResponse.json({ error: "Invalid Refresh Token" }, { status: 403 });
  }

  const currentToken = await db.query.refresh_tokens.findFirst({
    where: eq(refresh_tokens.username, decoded.username),
  });

  if (!currentToken) {
    return NextResponse.json({ error: "Refresh token not found" }, { status: 403 });
  }

  const isTokenValid = await Bun.password.verify(refresh_token, currentToken.refresh_token);
  if (!isTokenValid) {
    return NextResponse.json({ error: "Invalid Refresh Token" }, { status: 403 });
  }

  const user = await db.query.users.findFirst({
    where: eq(users.username, decoded.username)
  });
  
    const access_token = jwt.sign({
        username: user?.username,
        title: user?.title,
        perm: user?.permission
    }, process.env.JWT_AT_SECRET as string, { expiresIn: '1h' });

  return NextResponse.json({ access_token: access_token }, { status: 200 });
};
/refresh route
i used ai to make it better
@Brown bear @American Chinchilla
Golden northern bumble beeOP
@American Chinchilla @Brown bear
@Golden northern bumble bee <@338093833877323798> <@381550988110069760>
Asian black bear
Please stop constantly pinging users and be patient. They will respond at their own pace if they desire to do so.
Asian black bear
I was referring to you pinging the same people within 12h which is rude.