Skip to content

Latest commit

Β 

History

History
459 lines (397 loc) Β· 10.1 KB

File metadata and controls

459 lines (397 loc) Β· 10.1 KB

πŸ” Authentication & Security

Overview

Secure user authentication using Google OAuth2, JWT tokens, session management, and comprehensive security measures for enterprise-grade protection.


✨ Key Features

1. Google OAuth2

  • Secure third-party authentication
  • No password storage required
  • Single Sign-On (SSO)
  • Token-based sessions

2. JWT Authentication

  • Stateless authentication
  • Token expiration
  • Refresh token support
  • Secure token storage

3. Session Management

  • Persistent sessions
  • Auto-logout on expiry
  • Multiple device support
  • Session revocation

4. Security Headers

  • CORS protection
  • CSRF prevention
  • XSS protection
  • Helmet.js integration

🎯 Authentication Flow

Login Process

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  User clicks    β”‚
β”‚ "Login Google"  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Redirect to     β”‚
β”‚ Google OAuth    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ User Authorizes β”‚
β”‚  Permissions    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Callback with   β”‚
β”‚   Auth Code     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Exchange Code   β”‚
β”‚  for Tokens     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Create User     β”‚
β”‚  in Database    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Generate JWT    β”‚
β”‚    Token        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Store in        β”‚
β”‚  HttpOnly       β”‚
β”‚   Cookie        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Redirect to     β”‚
β”‚      IDE        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”§ Technical Details

Components

backend/src/controllers/auth.controller.js   # OAuth handlers
backend/src/middleware/auth.middleware.js    # JWT verification
backend/src/models/User.js                   # User schema
backend/src/utils/jwt.js                     # Token generation
frontend/src/services/authService.js         # Auth client
frontend/src/contexts/AuthContext.jsx        # Auth state

JWT Token Structure

{
  // Header
  "alg": "HS256",
  "typ": "JWT",
  
  // Payload
  "userId": "507f1f77bcf86cd799439011",
  "email": "user@example.com",
  "name": "John Doe",
  "iat": 1699527600,  // Issued at
  "exp": 1699614000   // Expires (24 hours)
}

API Endpoints

// Authentication
GET  /auth/google              # Initiate OAuth
GET  /auth/google/callback     # OAuth callback
POST /auth/logout              # Sign out
GET  /auth/me                  # Get current user
POST /auth/refresh             # Refresh token

// Protected routes (require JWT)
GET  /api/v1/projects          # Needs auth
POST /api/v1/files             # Needs auth

πŸš€ Implementation Details

1. OAuth2 Configuration

// backend/src/controllers/auth.controller.js
const oauth2Client = new google.auth.OAuth2(
  process.env.GOOGLE_CLIENT_ID,
  process.env.GOOGLE_CLIENT_SECRET,
  process.env.GOOGLE_REDIRECT_URI
);

// Generate auth URL
const authUrl = oauth2Client.generateAuthUrl({
  access_type: 'offline',
  scope: [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/userinfo.profile',
    'https://www.googleapis.com/auth/drive.file'
  ],
  prompt: 'consent'
});

2. JWT Generation

// backend/src/utils/jwt.js
function generateToken(user) {
  return jwt.sign(
    {
      userId: user._id,
      email: user.email,
      name: user.name
    },
    process.env.JWT_SECRET,
    {
      expiresIn: '24h',
      issuer: 'ai-ide',
      audience: 'ai-ide-users'
    }
  );
}

3. Token Verification Middleware

// backend/src/middleware/auth.middleware.js
async function authenticateToken(req, res, next) {
  try {
    // Extract token from cookie or header
    const token = req.cookies.token || 
                  req.headers.authorization?.split(' ')[1];
    
    if (!token) {
      return res.status(401).json({ 
        success: false, 
        message: 'No token provided' 
      });
    }
    
    // Verify token
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    
    // Attach user to request
    req.user = await User.findById(decoded.userId);
    
    if (!req.user) {
      return res.status(401).json({ 
        success: false, 
        message: 'User not found' 
      });
    }
    
    next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      return res.status(401).json({ 
        success: false, 
        message: 'Token expired' 
      });
    }
    res.status(403).json({ 
      success: false, 
      message: 'Invalid token' 
    });
  }
}

4. Frontend Auth Context

// frontend/src/contexts/AuthContext.jsx
export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    // Check if user is logged in
    checkAuth();
  }, []);
  
  async function checkAuth() {
    try {
      const response = await api.get('/auth/me');
      setUser(response.data.user);
    } catch (error) {
      setUser(null);
    } finally {
      setLoading(false);
    }
  }
  
  async function login() {
    window.location.href = '/auth/google';
  }
  
  async function logout() {
    await api.post('/auth/logout');
    setUser(null);
    window.location.href = '/';
  }
  
  return (
    <AuthContext.Provider value={{ user, loading, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

πŸ”’ Security Measures

1. Token Security

// HttpOnly cookies (prevent XSS)
res.cookie('token', jwtToken, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 24 * 60 * 60 * 1000 // 24 hours
});

// Encrypted token storage in DB
const encryptedToken = crypto.encrypt(refreshToken, SECRET_KEY);

2. CORS Configuration

// backend/src/index.js
app.use(cors({
  origin: process.env.FRONTEND_URL || 'http://localhost:3000',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

3. Rate Limiting

// backend/src/middleware/rateLimiter.js
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per window
  message: 'Too many requests, please try again later',
  standardHeaders: true,
  legacyHeaders: false
});

app.use('/api/', limiter);

4. Security Headers (Helmet)

// backend/src/index.js
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  }
}));

5. Input Validation

// Using express-validator
const { body, validationResult } = require('express-validator');

app.post('/api/v1/files',
  authenticateToken,
  [
    body('filename').trim().notEmpty().escape(),
    body('content').trim()
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // Process request
  }
);

βš™οΈ Configuration

Environment Variables

# backend/.env
JWT_SECRET=your_very_secure_random_secret_key_here
SESSION_SECRET=another_random_secret_for_sessions

GOOGLE_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-abcdefghijklmnop
GOOGLE_REDIRECT_URI=http://localhost:3001/auth/google/callback

# Token expiration
JWT_EXPIRES_IN=24h
REFRESH_TOKEN_EXPIRES_IN=7d

# Security
NODE_ENV=production
FRONTEND_URL=https://yourdomain.com

πŸ“Š User Schema

// backend/src/models/User.js
const UserSchema = new Schema({
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    trim: true
  },
  name: {
    type: String,
    required: true
  },
  googleId: {
    type: String,
    required: true,
    unique: true
  },
  avatar: String,
  refreshToken: {
    type: String,
    select: false // Don't return in queries
  },
  lastLogin: {
    type: Date,
    default: Date.now
  },
  createdAt: {
    type: Date,
    default: Date.now
  }
});

πŸ› Troubleshooting

Issue: Token expired

Solution:

// Implement token refresh
if (error.response?.status === 401) {
  const newToken = await refreshAccessToken();
  // Retry original request with new token
}

Issue: CORS errors

Solution:

// Check CORS configuration
// Ensure FRONTEND_URL matches exactly
// Include credentials: true in fetch
fetch(url, {
  credentials: 'include'
});

Issue: OAuth callback fails

Solution:

# Verify redirect URI in Google Console
# Must match EXACTLY (including http/https, port)
http://localhost:3001/auth/google/callback

# Check OAuth credentials
cat backend/.env | grep GOOGLE

πŸ“– References