Back to articles

Modern Authentication with React and Serverless Functions

AuthorMajd Muhtaseb08/31/20257 minutes
Modern Authentication with React and Serverless Functions

Introduction

Building authentication from scratch can be daunting. This article provides a streamlined approach to implementing secure authentication in your React application using serverless functions. We'll focus on the core concepts and provide code snippets to get you started quickly.

Choosing a Serverless Provider

Many providers offer serverless function capabilities. Examples include:

  • Netlify Functions
  • AWS Lambda
  • Firebase Cloud Functions
  • Vercel Functions

For this example, let's assume we're using Netlify Functions for simplicity. The concepts translate well to other providers.

Setting up the Serverless Function (Example - Node.js)

Create a netlify/functions/authenticate.js file:

// netlify/functions/authenticate.js
exports.handler = async (event, context) => {
  // Simulate user authentication (replace with real logic)
  const { username, password } = JSON.parse(event.body);

  if (username === 'testuser' && password === 'password123') {
    return {
      statusCode: 200,
      body: JSON.stringify({
        message: 'Authentication successful',
        token: 'fake-jwt-token', // In reality, generate a real JWT
      }),
    };
  } else {
    return {
      statusCode: 401,
      body: JSON.stringify({ message: 'Invalid credentials' }),
    };
  }
};

Remember to install the required dependencies if any.

React Frontend Implementation

Create a simple React component:

// src/components/Login.js
import React, { useState } from 'react';

function Login() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [token, setToken] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = async (event) => {
    event.preventDefault();

    try {
      const response = await fetch('/.netlify/functions/authenticate', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password }),
      });

      const data = await response.json();

      if (response.ok) {
        setToken(data.token);
        setError('');
      } else {
        setError(data.message);
        setToken('');
      }
    } catch (err) {
      setError('An error occurred during authentication.');
      setToken('');
      console.error(err);
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <div>
          <label htmlFor="username">Username:</label>
          <input
            type="text"
            id="username"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
        </div>
        <div>
          <label htmlFor="password">Password:</label>
          <input
            type="password"
            id="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>
        <button type="submit">Login</button>
      </form>

      {error && <p style={{ color: 'red' }}>{error}</p>}
      {token && <p>Authentication Token: {token}</p>}
    </div>
  );
}

export default Login;

Securing Routes (Example)

After successful authentication, store the token (e.g., in localStorage or a cookie). Use this token to protect routes in your application. A simple example would involve checking for the presence of this token to determine the rendering of components.

Conclusion

This article provides a basic framework for modern authentication using React and serverless functions. Remember to replace the dummy authentication logic with a robust solution that handles user registration, password management, and secure token generation/validation. Serverless functions are a powerful tool for building scalable and secure authentication systems.