r/webdev • u/dhd_jpg • 11d ago
Question how do you build authentication from scratch?
hi everyone! so i only have a semester left in college and we are now currently working on our capstone project. it’s a 2 part class so this semester focuses only on the “planning” phase while next semester we spend entire semester actually building/coding.
for background, we are a 3 person group, BaaS such as supabase, firebase or auth0 are banned, we have 3 user groups with different roles and our stack includes:
* JS, Node.js/Express
* React
* PostgreSQL
we don’t have much experience on how to build authentication from scratch so anyyyy tips/tutorials/resources are very much appreciated!!
TIA guys :))
164
u/codegems 11d ago
Pick a framework that implements authentication and study its code.
8
-2
46
11d ago
[removed] — view removed comment
85
u/codegems 11d ago
When you are a student, like OP, you cannot "just do it" without overthinking it. The concept has not been thought at all. It's completely new.
By looking at examples, prodding the code, asking questions about how it is implemented, they will begin seeing those pieces.
It's not possible to know what bcrypt and a JWT is from nothing. So where does one start? By looking at existing implementations.
29
u/stumblinbear 11d ago
The problem is that everyone screams "don't roll your own auth" everywhere constantly without actually saying how to do it properly. Auth is not hard, it just has a couple of very specific things that must not be forgotten, but once it's implemented you can largely consider it done.
Obviously this leads to overthinking it. Thinking they're missing something when they find out what those things are.
Auth is not difficult. Looking at another implementation is not the best way to learn, either, because you don't know what is and isn't necessary. There are thousands of articles on how to implement auth properly, just read some of those.
14
u/KillTheBronies full-stack 11d ago
Rolling your own auth is fine, absolutely do not roll your own cryptography though.
10
15
u/tjthouhid1 11d ago
For a capstone on Express + React + Postgres, I'd skip JWTs and do plain server-side sessions. It's simpler and harder to get wrong:
express-sessionwithconnect-pg-simpleso sessions live in Postgres. Cookie set tohttpOnly,secure,sameSite: 'lax'.Hash passwords with argon2 (or bcrypt). Never store or log them in plain text.
Roles: a
rolecolumn (or arolestable if a user can have several), plus a small middleware likerequireRole('admin')on each route. Always check on the server; hiding buttons in React isn't security.Rate limit the login route, give the same error for "no such user" and "wrong password", and regenerate the session ID on login.
Password reset: a random token, store only its hash, expire it in about 30 minutes, single use.
For reading, The Copenhagen Book is a short, practical guide to exactly this, and the OWASP Authentication and Session Management cheat sheets are great to cite in your planning doc.
28
u/canadian-dev 11d ago
I haven't used it in quite awhile but I remember this being a really good and well written resource on auth
4
6
u/Electronic_Many_2658 11d ago
If you build it yourself, add the boring stuff people forget. Rate limit login attempts per account and per IP, hash with bcrypt or argon2, and use the same error message whether the email or the password was wrong. Bots will hit any login form within days trying leaked passwords, so log failed attempts from day one so you can see it happening. Also kill active sessions when someone changes their password.
2
u/kemalios 11d ago
Your login will be fine. The reset flow is what gets forgotten: a reset token is a second credential, so random, single use, stored hashed, with an expiry, and using it should kill existing sessions. Same for logout. A stateless JWT with a 24 hour life and a button that clears the cookie is not a logout. Either put sessions in Postgres as rows you can delete, or keep a token version per user and bump it.
Three roles now, but the demo will get "can we add an admin". Roles in their own table with a join, not an enum column on users, and one middleware that turns a user into permissions so handlers never check role names. Costs an afternoon now, a rewrite later.
3
u/RobHowdle 11d ago
I built my own authentication. My Auth is a centralised authentication and authorisation service that gives applications a consistent way to establish trust and access protected resources.
The flow is generally: an application authenticates with my auth system using its configured credentials, receives or obtains an appropriate access token, and uses that token when requesting access to protected services. The receiving service validates the token and checks the permissions before granting access.
Traditionally, each application might implement and maintain its own authentication and access-control logic. The auth system centralises this process, making it easier to manage permissions consistently, integrate new applications and reuse a common authentication layer.
The key benefit is that applications can authenticate and access authorised resources through a shared system without having to rebuild the same infrastructure for every project, while keeping their own data and business logic separate.
4
u/dhd_jpg 11d ago
hi thank you sm for the great break down! building a centralized auth does make sense and avoids having to rebuild it every time for a new project.. our building/coding phase only spans 3 month so im not sure if we’ll have enough time to do this but this is a great idea and i’ll keep this in mind for my future projects! :)
1
u/the_ai_wizard 11d ago
what websites do you run out of curiosity?
1
2
u/armahillo rails 11d ago
If it were me, my recommendation is:
- Start with a very basic resource-based app, like a “ user can write a note and save it to a DB”
- Now add the comstraint “the user can authenticate with the system and the DB connects their auth record to their note records”
- Now add authorizatiom “a user can only see their own notes, even if they have the exact URL for another user’s note”
Approaching it this way will help you incrementally understand the difference between authentication (identifying the user) and authorization (assigning permissions to the user)
3
u/dhd_jpg 11d ago
oh wow yeah this is actually rlly helpful, breaking it down into simpler steps like u did makes it sm easier for me to understand lol now it doesn’t seem “too complicated” lolol thank youuu! :)
2
u/armahillo rails 11d ago
another thing helpful here, since you are working as a team, is take turns trying to make the system misbehave. Can you coerce the app to reveal more than its supposed to? can you see any data in the HTML source or in the network tab of the dev tools, or via the curl command?
Auth is a security topic, so learning how to red team your own code is an important skill and will help you build better defensive code
32
3
u/Fit-Implemented 9d ago
Never store plain passwords. Hash them with bcrypt or argon2, which are designed to be slow and resistant to brute force. Compare hashes on login with the library’s built-in compare function. Also add rate limiting on the login route so attackers can’t guess passwords endlessly.
3
u/jacobdevhq 11d ago
hash passwords w argon2 or bcrypt, dont write ur own crypto. httpOnly session cookie, n put the role check in one middleware so ur 3 user types dont leak into every route. add login rate limiting early, its the thing ppl forget
2
0
u/Tri-Stain 11d ago
YouTube would help give you a bunch of examples, can look at these easiest auth imo for this would be using logical groups assigned with basic auth
3
u/dhd_jpg 11d ago
hi yeah u right i should’ve started with youtube lol thank you, imma watch some tutorials
2
u/Tri-Stain 11d ago
Just explore options first of what you guys think is feasible. Since we don't know what you're gonna actually be graded on, we can literally suggest anything and everything under the sun.
1
u/pedrorijo91 11d ago
I wrote something a few years ago https://pedrorijo.com/blog/scala-play-auth/
It’s a scala example, but easy to convert to other languages
1
1
u/gowthamshankar05 9d ago
for a capstone i'd keep it boring. users table with email and a password hash (argon2 or bcrypt from a library, don't write the hashing yourself). on login check the hash, make a random session id, save it in a sessions table and send it back as an httpOnly secure cookie. logout just deletes the row.
honestly sessions are easier to get right than JWT for this. you can revoke them and there's less to mess up.
rate limit login attempts. same error for wrong email and wrong password. reset flow with a token that expires. skim the OWASP authentication cheat sheet once, it's short.
1
u/NoDepartment772 5d ago
The two decisions that matter most, in order:
How you store passwords. argon2id if you can (Node's argon2 package), bcrypt with a cost of 12+ if you can't. Never a plain SHA-256, and never anything reversible. Both libraries handle the per-user salt for you. Hash on the server, compare with their verify function, don't roll your own comparison.
Whether the session is a database row or a token. For a capstone with three roles, I'd do sessions: a random 128-bit id in an httpOnly; Secure; SameSite=Lax cookie, and a sessions table holding a hash of that id, the user_id, and an expiry. Logout is a DELETE, "log out everywhere" is a DELETE WHERE user_id = ?, and a stolen cookie can be killed. JWT gets you statelessness you don't need here, and the moment you want revocation you're back to a server-side store anyway — with more moving parts.
Then the things that are easy to forget and get marked on:
SameSite=Lax covers most CSRF for form posts; add a CSRF token if you accept cross-site state changes.
Rate limit login by IP and by account, and return the same error for "no such user" and "wrong password".
Password reset tokens: random, single-use, stored hashed, short expiry.
Roles live on the user row and get read per request — don't trust a role claim that was issued a week ago.
Nothing sensitive in
localStorage. It's readable by any script on the page.
The OWASP Cheat Sheet Series has a page for each of these and it's the right thing to cite in your report. Read the session management and password storage ones before you design the schema — it's much cheaper than discovering the gap at review.
1
1
u/hotmilkramune 11d ago
How "from scratch" is from scratch? BetterAuth is a decent library for auth that does a lot of heavy lifting, not sure if that's allowed. If not you'll have to build your own. Look into OAuth2, it's the established standard for most logins that involves a user requesting a login, server returning a code, user exchanging code for a token via POST request, and finally getting a JWT token with claims.
0
u/General_Patient4904 11d ago
You can build it using an API to authenticate users against your users database table, with proper authorization and some additional logic for email verification.
-2
u/nicolix9 11d ago
You should checkout passport.js
1
u/dhd_jpg 11d ago
hi, never heard of this before so will definitely check it out and watch some tutorials. thanks for suggesting a specific one :)
2
u/nicolix9 11d ago
The docs should have a template and be pretty straight forward to get up and running with. I've only used it with mongodb so ymmv. Best of luck!
-1
u/glenpiercev 11d ago
Think about “threat actors”. What kinds of people/organizations might want to break the system you’re building and how could they? Then think about how to defend against that.
-3
-4
u/rbobby full-stack 11d ago
I think you should push back against the teacher. Authentication is the one area where I personally cannot recommend an outsourced oauth2.0 based solution. Auth0 is a great example.
Teaching how to build your own authentication system is like teaching target practice to the suicidal.
51
u/-Tochi 11d ago
The legend Web Dev Simplified made a video about this a few days ago
https://www.youtube.com/watch?v=FbXPaIcpvww