What is Authentication?

Authentication (often shortened to "AuthN") is the process of verifying that a user is who they claim to be. It's about proving identity. When you type your password to log in to a service, you are authenticating.

Flow 1: Classic Email & Password

This is the most traditional form of authentication. The user provides an email/username and a password, and the server checks if they match a stored record.

The Golden Rule: NEVER, EVER Store Plaintext Passwords.

If your database is ever compromised and you have stored passwords in plaintext, an attacker will have the keys to every user's account—and likely their accounts on other sites, as people reuse passwords.

The Solution: Password Hashing Instead of storing the password, you store a hash of the password. A hashing function is a one-way algorithm: it's easy to compute a hash from a password, but computationally infeasible to go from the hash back to the original password.

For this, we use a strong, slow, and adaptive algorithm like bcrypt.

  • Slow: It's intentionally slow to make brute-force attacks (trying millions of passwords per second) much more difficult.
  • Adaptive: It can be made slower as computers get faster.
  • Salted: It automatically incorporates a "salt" (a random string) into the hash, ensuring that two users with the same password will have completely different hashes.

Code Snippet: Using bcrypt in Node.js

  • User Registration (Hashing the password):

JavaScript


import bcrypt from 'bcrypt';

app.post('/register', async (req, res) => {
  const { email, password } = req.body;
  const saltRounds = 10; // The cost factor - how complex the hash is

  // Hash the password before saving it to the database
  const hashedPassword = await bcrypt.hash(password, saltRounds);

  // Store the email and hashedPassword in your 'users' table
  await db.users.create({ email, password: hashedPassword });

  res.status(201).send('User created');
});
  • User Login (Comparing the password):

JavaScript


app.post('/login', async (req, res) => {
  const { email, password } = req.body;
  
  // Find the user by their email
  const user = await db.users.findByEmail(email);
  if (!user) {
    return res.status(401).send('Authentication failed');
  }

  // Compare the submitted password with the stored hash
  const isMatch = await bcrypt.compare(password, user.hashedPassword);

  if (isMatch) {
    // Passwords match! Create a session for the user.
    req.session.userId = user.id;
    res.send('Logged in successfully');
  } else {
    // Passwords do not match.
    res.status(401).send('Authentication failed');
  }
});

Flow 2: OAuth 2.0 (Social Logins)

OAuth 2.0 is not authentication; it's an authorization framework. However, it's commonly used to build authentication flows, such as "Login with Google" or "Login with Facebook."

Think of it as delegated access. You are giving an application permission to access certain parts of your account on another service without giving it your password.

The High-Level Flow:

  1. User Clicks "Login with Google": Your application (the "Client") redirects the user to Google's login page (the "Authorization Server").
  2. User Consents: The user logs in to their Google account and sees a consent screen saying "[Your App] would like to access your name and email address." The user clicks "Allow."
  3. Google Redirects with a Code: Google redirects the user back to your application with a temporary, one-time-use authorization code in the URL.
  4. Server Exchanges Code for Token: Your server takes this authorization code and sends it directly to Google's server. Google verifies the code and sends back an access token.
  5. Server Fetches User Info: Your server can now use this access token to make API calls to Google to fetch the user's profile information (name, email, profile picture).
  6. App Authenticates User: Once your server has the verified user information from Google, it can find or create a local account for that user and establish a session for them.

This entire flow is complex to implement from scratch. Libraries like Passport.js in the Node.js ecosystem make it much easier by providing "strategies" for Google, Facebook, GitHub, and hundreds of other providers.