Authentication is the bouncer at the door of your application. Every time someone signs up or logs in, your system has to decide whether they are who they claim to be. Get it wrong, and you are not just debugging a failed login. You are risking real user data walking straight out the door. Doing this properly requires two reliable tools: Bcrypt for guarding passwords at rest, and JSON Web Tokens for verifying identity while the user moves around your app.
Why Plaintext Storage Fails
If you take only one rule away from this article, make it this one: never store passwords as plaintext in your database. It does not matter if your database is behind a firewall or if you trust every engineer on the team. Writing passwords into tables in their raw form is like leaving house keys under a welcome mat. The moment someone gains access to that database—through a misconfigured API, a leaked backup, or an injection attack—every credential is exposed instantly.
The damage multiplies because people reuse passwords. A single breach can compromise not just your application, but a user’s email, banking, and social media accounts. This is why we hash passwords. Hashing transforms the password into a scrambled string that bears no obvious resemblance to the original. The process is one-way and irreversible. You cannot pour mathematical acid on a hash and dissolve it back into the password that created it.
Hashing Passwords with Bcrypt
Bcrypt is a hashing function built specifically for passwords. It takes the plain string, runs it through the Blowfish cipher, and hands back a result that looks something like $2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy. That prefix tells you the algorithm and cost factor. The long tail is a combination of the salt and the hash itself.
The salt is random data blended into the password before hashing begins. Because the salt is unique for every user, two people who both choose "password123" will end up with completely different hashes in your database. This trivial difference defeats rainbow tables—precomputed dictionaries of hashes for common passwords—because attackers would need to regenerate the entire table for every unique salt.
Bcrypt is also intentionally slow. Modern hardware can guess billions of hashes per second with fast algorithms like SHA-256. Bcrypt drags its feet. It runs the hashing process multiple times, controlled by a cost factor that you can raise as computers get faster. That slowness punishes anyone trying to brute-force their way through a stolen database. A legitimate user waiting an extra two hundred milliseconds during login will not notice. An attacker trying to test millions of guesses certainly will.
How JSON Web Tokens Work
While Bcrypt handles the front door, JWT handles the hallway pass. A JSON Web Token is a compact, URL-safe string that proves a user has already been authenticated. Think of it as a digital ID card that the server issues and the client carries around.
A JWT contains three segments separated by dots: the header, the payload, and the signature. The header specifies the token type and the signing algorithm. The payload carries claims—statements about the user and the token itself—such as a user ID, username, and an expiration timestamp. The signature is the cryptographic seal. The server creates it by encoding the header and payload, then running them through a secret key. If anyone tampers with the payload, the signature no longer matches, and the server rejects the token outright.
