How to Add User Authentication to Your Web App (Google & Email Login)
OtterAI Team
11 min read

How to Add User Authentication to Your Web App (Google & Email Login)

Complete guide to implementing user authentication with Google Sign-In and email/password login. Security best practices and code examples included.

#Tutorial#Authentication#Security

User authentication is one of the most critical features of modern web applications. Whether you're building a SaaS product, social platform, or membership site, you need a way for users to create accounts, log in securely, and access their data.

This guide will walk you through everything you need to know about implementing authentication, from basic concepts to production-ready implementation.

What is User Authentication?

Authentication is the process of verifying that users are who they claim to be. It typically involves:

  1. Registration - Users create an account
  2. Login - Users prove their identity
  3. Session management - Keeping users logged in
  4. Authorization - Controlling what users can access

Why Authentication Matters

Security

  • Protect user data
  • Prevent unauthorized access
  • Comply with regulations (GDPR, CCPA)

Personalization

  • Save user preferences
  • Display personalized content
  • Track user activity

Business value

  • Build user relationships
  • Enable paid features
  • Gather analytics

Authentication Methods Explained

Email/Password (Traditional)

How it works:

  1. User provides email and password
  2. Password is hashed and stored
  3. On login, password is verified
  4. Session is created

Pros:

  • Users understand it
  • No third-party dependency
  • Complete control

Cons:

  • Users forget passwords
  • Security responsibility is yours
  • Need password reset flow
  • Vulnerable to attacks if not done right

Social Login (OAuth)

Popular providers:

  • Google
  • Facebook
  • GitHub
  • Twitter/X
  • Apple
  • Microsoft

How it works:

  1. User clicks "Sign in with Google"
  2. Redirected to Google
  3. User authorizes your app
  4. Google sends back user info
  5. You create/log in the user

Pros:

  • Faster registration
  • No password to manage
  • Provider handles security
  • Get user profile data

Cons:

  • Depends on third party
  • User needs provider account
  • Privacy concerns for some
  • Setup required for each provider

Magic Links (Passwordless)

How it works:

  1. User enters email
  2. You send login link
  3. User clicks link
  4. Automatically logged in

Pros:

  • No passwords to forget
  • Very secure
  • Simple UX

Cons:

  • Requires email access
  • Can be slower
  • Email delays
  • Spam folder issues

Multi-Factor Authentication (MFA)

Add extra security layer:

  • SMS code
  • Authenticator app
  • Email verification
  • Biometrics

When to use: Sensitive data, financial apps, admin access

What You Need to Build

Authentication flow diagram

A complete authentication system needs:

  1. Registration page

    • Email/password form
    • Validation
    • Account creation
  2. Login page

    • Sign-in form
    • Social login buttons
    • "Forgot password" link
  3. Password reset flow

    • Reset request page
    • Email with reset link
    • New password page
  4. Protected routes

    • Check if user is logged in
    • Redirect if not authenticated
  5. User profile/dashboard

    • Display user info
    • Account settings
    • Logout button
  6. Session management

    • Keep users logged in
    • Automatic logout after inactivity
    • Remember device
  7. Database

    • Store user accounts
    • Hash passwords
    • Store sessions

Traditional Implementation Approach

Step 1: Database Setup

Create a users table:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email VARCHAR(255) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  google_id VARCHAR(255),
  created_at TIMESTAMP DEFAULT NOW(),
  last_login TIMESTAMP
);

Step 2: Password Hashing

NEVER store plain text passwords!

const bcrypt = require('bcrypt');

// Registration
const saltRounds = 10;
const hashedPassword = await bcrypt.hash(password, saltRounds);

// Login verification
const isValid = await bcrypt.compare(password, user.password_hash);

Step 3: Registration Endpoint

app.post('/register', async (req, res) => {
  const { email, password } = req.body;
  
  // Validation
  if (!email || !password) {
    return res.status(400).json({ error: 'Email and password required' });
  }
  
  if (password.length < 8) {
    return res.status(400).json({ error: 'Password must be 8+ characters' });
  }
  
  // Check if user exists
  const existing = await db.query('SELECT * FROM users WHERE email = $1', [email]);
  if (existing.rows.length > 0) {
    return res.status(400).json({ error: 'Email already registered' });
  }
  
  // Hash password
  const passwordHash = await bcrypt.hash(password, 10);
  
  // Create user
  const result = await db.query(
    'INSERT INTO users (email, password_hash) VALUES ($1, $2) RETURNING id, email',
    [email, passwordHash]
  );
  
  // Create session
  req.session.userId = result.rows[0].id;
  
  res.json({ user: result.rows[0] });
});

Step 4: Login Endpoint

app.post('/login', async (req, res) => {
  const { email, password } = req.body;
  
  // Find user
  const result = await db.query('SELECT * FROM users WHERE email = $1', [email]);
  const user = result.rows[0];
  
  if (!user) {
    return res.status(401).json({ error: 'Invalid email or password' });
  }
  
  // Verify password
  const isValid = await bcrypt.compare(password, user.password_hash);
  
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid email or password' });
  }
  
  // Create session
  req.session.userId = user.id;
  
  // Update last login
  await db.query('UPDATE users SET last_login = NOW() WHERE id = $1', [user.id]);
  
  res.json({ user: { id: user.id, email: user.email } });
});

Step 5: Google OAuth Setup

const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/callback"
  },
  async (accessToken, refreshToken, profile, done) => {
    // Find or create user
    let user = await db.query('SELECT * FROM users WHERE google_id = $1', [profile.id]);
    
    if (user.rows.length === 0) {
      // Create new user
      user = await db.query(
        'INSERT INTO users (email, google_id) VALUES ($1, $2) RETURNING *',
        [profile.emails[0].value, profile.id]
      );
    }
    
    return done(null, user.rows[0]);
  }
));

// Routes
app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

app.get('/auth/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login' }),
  (req, res) => {
    res.redirect('/dashboard');
  }
);

Step 6: Protect Routes

function requireAuth(req, res, next) {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
}

// Protected route
app.get('/dashboard', requireAuth, (req, res) => {
  res.json({ message: 'Welcome to dashboard' });
});

Complexity: This is just the basics! You still need:

  • Password reset flow
  • Email verification
  • CSRF protection
  • Rate limiting
  • Session security
  • Error handling
  • Frontend forms and validation
  • Testing

Time to implement properly: 20-40 hours for someone experienced

Modern Authentication Services

Instead of building from scratch, use authentication-as-a-service:

Clerk

Features:

  • Pre-built UI components
  • Email/password & social login
  • Session management
  • User profiles
  • Multi-factor authentication

Pricing:

  • Free: 10,000 monthly active users
  • Pro: $25/month + usage

Setup time: 15-30 minutes

Auth0

Features:

  • Enterprise-grade
  • Extensive customization
  • Many authentication methods
  • Advanced security

Pricing:

  • Free: 7,500 active users
  • Paid: Starts at $23/month

Supabase Auth

Features:

  • Open source
  • Built on PostgreSQL
  • Row-level security
  • Easy integration

Pricing:

  • Free tier available
  • Pro: $25/month

Firebase Authentication

Features:

  • Google's solution
  • Many providers
  • Real-time integration
  • Mobile + web

Pricing:

  • Free tier generous
  • Pay as you go

Security Best Practices

Password Requirements

Do:

  • Minimum 8 characters (12+ is better)
  • Allow long passwords (64+ characters)
  • Allow special characters
  • Check against common passwords
  • Use zxcvbn for strength checking

Don't:

  • Force complex requirements (users make weak patterns)
  • Limit maximum length (prevents passphrases)
  • Prevent paste (hurts password managers)
  • Expire passwords arbitrarily

Secure Storage

NEVER:

  • Store passwords in plain text
  • Use MD5 or SHA1 for passwords
  • Use weak salts
  • Store sensitive data unencrypted

ALWAYS:

  • Use bcrypt, scrypt, or Argon2
  • Use unique salts per user
  • Encrypt sensitive data
  • Use HTTPS everywhere

Session Security

Best practices:

  • Use secure, httpOnly cookies
  • Implement CSRF protection
  • Set appropriate session timeout
  • Regenerate session ID after login
  • Clear session on logout

Rate Limiting

Prevent brute force attacks:

const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // limit each IP to 5 requests per windowMs
  message: 'Too many login attempts, please try again later'
});

app.post('/login', loginLimiter, async (req, res) => {
  // login logic
});

Input Validation

Always validate and sanitize:

const validator = require('validator');

// Email validation
if (!validator.isEmail(email)) {
  return res.status(400).json({ error: 'Invalid email' });
}

// Sanitize input
const sanitizedEmail = validator.normalizeEmail(email);

Implementing with Modern Tools

Instead of writing all this code, describe what you need:

"Create user authentication with email/password and Google sign-in. Include registration, login, password reset, and protected dashboard. Use Clerk for authentication and style it to match my brand colors."

Modern AI tools can generate:

  • Complete authentication flow
  • Frontend components (login/register forms)
  • Backend API routes
  • Database schema
  • Session management
  • Protected routes
  • All security best practices

Time: 15-30 minutes instead of days

Common Authentication Features

Email Verification

Force users to verify email before full access:

  1. Send verification email on registration
  2. Include unique token in link
  3. Mark email as verified when clicked
  4. Limit features until verified

Password Reset

Secure password reset flow:

  1. User requests reset
  2. Generate unique token
  3. Send email with reset link
  4. Token expires after time (1 hour)
  5. Allow new password setting
  6. Invalidate old sessions

Remember Me

Keep users logged in:

// Extend session duration
if (rememberMe) {
  req.session.cookie.maxAge = 30 * 24 * 60 * 60 * 1000; // 30 days
} else {
  req.session.cookie.maxAge = null; // Session cookie
}

Account Deletion

Allow users to delete accounts (GDPR requirement):

  1. Confirm user identity
  2. Warn about data loss
  3. Delete or anonymize data
  4. Send confirmation email

Testing Your Authentication

Before going live:

Security Testing

  • Try SQL injection in forms
  • Test XSS attacks
  • Verify HTTPS everywhere
  • Check password hashing
  • Test session timeout
  • Verify logout works
  • Test CSRF protection

Functionality Testing

  • Register new account
  • Login with correct credentials
  • Login with wrong password
  • Login with non-existent email
  • Google sign-in flow
  • Password reset flow
  • Email verification
  • Access protected routes
  • Logout
  • Session persistence

Edge Cases

  • Account already exists
  • Concurrent logins
  • Expired sessions
  • Invalid tokens
  • Network errors
  • Database failures

Troubleshooting Common Issues

"Invalid credentials" on correct password

Causes:

  • Password not hashed correctly
  • Comparing wrong values
  • Database encoding issues

Solution: Log hashes (temporarily) to debug

Sessions not persisting

Causes:

  • Cookie not set
  • HTTPS/domain issues
  • Session store not configured

Solution: Check browser dev tools, verify session middleware

Google OAuth not working

Causes:

  • Wrong redirect URI
  • Invalid credentials
  • Scope issues

Solution: Check Google Console settings, verify callback URL

"CSRF token mismatch"

Causes:

  • Token not included in request
  • Token expired
  • Wrong configuration

Solution: Ensure token in forms, check middleware order

Going to Production

Production checklist:

Environment Variables

Never hardcode:

// .env file
DATABASE_URL=postgresql://...
SESSION_SECRET=long-random-string
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-secret

HTTPS

  • Get SSL certificate (free with Let's Encrypt)
  • Force HTTPS redirects
  • Set secure cookie flags

Monitoring

Set up:

  • Failed login alerts
  • Account creation monitoring
  • Session anomaly detection
  • Error logging

Compliance

Consider:

  • GDPR (if EU users)
  • CCPA (if California users)
  • Terms of service
  • Privacy policy
  • Cookie consent

Cost Comparison

Build It Yourself

Costs:

  • Development time: 20-40 hours @ $50-150/hr = $1,000-$6,000
  • Ongoing maintenance: 2-4 hours/month
  • Security audits: $500-$2,000/year
  • Total year 1: $1,500-$10,000

Use Authentication Service

Costs:

  • Setup time: 2-4 hours
  • Service fee: $0-$300/month
  • Minimal maintenance
  • Security included
  • Total year 1: $0-$3,600

Savings: Thousands of dollars and weeks of time

Conclusion

Authentication is complex and critical. Building it from scratch requires:

  • Deep security knowledge
  • Significant development time
  • Ongoing maintenance
  • Regular security updates

Modern authentication services handle all of this for you, letting you focus on your core product instead of reinventing authentication.

Key takeaways:

  • Never store plain text passwords
  • Use HTTPS everywhere
  • Consider authentication services
  • Test security thoroughly
  • Keep security updated
  • Follow best practices

Whether you build it yourself or use a service, get authentication right. Your users' security depends on it.


Need user authentication in your app? OtterAI can generate a complete authentication system with email/password and social login, including all security best practices - describe your requirements and we'll build it for you.

Related Articles