Script Valley
REST API Development: Complete Course from Beginner to Production
Authentication and Security in REST APIsLesson 4.4

Password Hashing, Token Storage, and Secure Practices

bcrypt, password hashing, salt rounds, token storage, httpOnly cookies, HTTPS, secret management, OWASP API security

Password Hashing, Token Storage, and Secure Practices

Authentication security is only as strong as its weakest implementation detail. Correct algorithm choices, storage patterns, and transmission security are what separate a secure REST API from a vulnerable one.

DiagramPassword Hashing with bcrypt

IMAGE PROMPT (replace this block with your generated image):

Flat two-section diagram on white background. Title: Secure Password Handling with bcrypt. Section 1 (top half): Registration flow. Steps: 1. User submits password (e.g. MyPass123) box. 2. Arrow to bcrypt.hash(password, 12) box (filled #3A5EFF, white text). 3. Arrow to hashed output box ($2b$12$xyz...) (dark text, monospace). 4. Arrow to database cylinder labeled Store ONLY the hash. Section 2 (bottom half): Login flow. Steps: 1. User submits password again box. 2. Arrow to bcrypt.compare(input, hash) box (filled #3A5EFF). 3. Two outcomes: green checkmark arrow labeled Match โ€” allow login, red X arrow labeled No match โ€” return 401. Separator between sections: dashed horizontal line with label Registration vs Login. Salt factor badge showing Recommended: 12 rounds in top right corner. White background, clean arrows, brand color #3A5EFF for function boxes.

Password Hashing with bcrypt

Never store plaintext passwords. Always hash passwords using bcrypt, which is specifically designed for passwords โ€” it is slow by design (making brute-force attacks expensive) and includes a built-in salt to prevent rainbow table attacks.

const bcrypt = require('bcryptjs');

userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 12);
  next();
});

userSchema.methods.comparePassword = async function(candidatePassword) {
  return bcrypt.compare(candidatePassword, this.password);
};

Use a salt factor of 10-12 for production. Higher values increase security but also increase CPU time per login. 12 is a reasonable balance for most applications.

Where to Store JWT Tokens

Storing JWTs in localStorage is vulnerable to XSS attacks โ€” any JavaScript running on the page can read localStorage. Storing them in httpOnly cookies makes them inaccessible to JavaScript, mitigating XSS. Use the Secure flag to ensure cookies are only sent over HTTPS.

res.cookie('refreshToken', refreshToken, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 7 * 24 * 60 * 60 * 1000
});

HTTPS Is Non-Negotiable

All REST API traffic in production must use HTTPS. HTTP transmits tokens and credentials in plaintext, making them trivially interceptable on any network. Use TLS certificates from Let's Encrypt (free) and enforce HTTPS redirection at the infrastructure level.

Secret Management

JWT secrets and database passwords must be randomly generated, stored in environment variables, rotated periodically, and managed with a secrets manager in production. A secret exposed in a Git commit must be rotated immediately, even if the commit was immediately deleted.

Up next

OAuth 2.0 and Social Login: Concepts and Integration

Sign in to track progress

Password Hashing, Token Storage, and Secure Practices โ€” Authentication and Security in REST APIs โ€” REST API Development: Complete Course from Beginner to Production โ€” Script Valley โ€” Script Valley