Create alternative of Next Auth
Published: 2024-06-25 14:01:22

Below is a fully functional example of how you can create an authentication system in a Next.js application without using NextAuth. This example uses JWT (JSON Web Tokens) for authentication and cookie-based session management.

### 1. Install Dependencies

First, install the required dependencies:

```bash
npm install next react react-dom bcryptjs jsonwebtoken cookie
```

### 2. Directory Structure

Your project structure should look like this:

```
/pages
  /api
    /auth
      login.js
      register.js
      logout.js
  /protected
    index.js
  _app.js
  index.js
/utils
  auth.js
  db.js
/middleware
  auth.js
```

### 3. Create a Simple User Database

For simplicity, let's create a fake user database.

#### `/utils/db.js`

```javascript
const users = [];

module.exports = {
  users,
};
```

### 4. Create Authentication Utilities

#### `/utils/auth.js`

```javascript
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const JWT_SECRET = 'your_jwt_secret';

const hashPassword = async (password) => {
  return await bcrypt.hash(password, 10);
};

const verifyPassword = async (password, hashedPassword) => {
  return await bcrypt.compare(password, hashedPassword);
};

const generateToken = (user) => {
  return jwt.sign({ id: user.id, email: user.email }, JWT_SECRET, { expiresIn: '1h' });
};

const verifyToken = (token) => {
  try {
    return jwt.verify(token, JWT_SECRET);
  } catch (error) {
    return null;
  }
};

module.exports = {
  hashPassword,
  verifyPassword,
  generateToken,
  verifyToken,
};
```

### 5. Create API Routes for Authentication

#### `/pages/api/auth/register.js`

```javascript
import { users } from '../../../utils/db';
import { hashPassword } from '../../../utils/auth';

export default async (req, res) => {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    const userExists = users.find(user => user.email === email);
    if (userExists) {
      return res.status(400).json({ message: 'User already exists' });
    }

    const hashedPassword = await hashPassword(password);
    const newUser = { id: users.length + 1, email, password: hashedPassword };
    users.push(newUser);

    res.status(201).json({ message: 'User registered successfully' });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
};
```

#### `/pages/api/auth/login.js`

```javascript
import { users } from '../../../utils/db';
import { verifyPassword, generateToken } from '../../../utils/auth';
import cookie from 'cookie';

export default async (req, res) => {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    const user = users.find(user => user.email === email);
    if (!user) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    const isValid = await verifyPassword(password, user.password);
    if (!isValid) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }

    const token = generateToken(user);

    res.setHeader('Set-Cookie', cookie.serialize('token', token, {
      httpOnly: true,
      secure: process.env.NODE_ENV !== 'development',
      maxAge: 3600,
      sameSite: 'strict',
      path: '/'
    }));

    res.status(200).json({ message: 'Logged in successfully' });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
};
```

#### `/pages/api/auth/logout.js`

```javascript
import cookie from 'cookie';

export default (req, res) => {
  if (req.method === 'POST') {
    res.setHeader('Set-Cookie', cookie.serialize('token', '', {
      httpOnly: true,
      secure: process.env.NODE_ENV !== 'development',
      maxAge: -1,
      sameSite: 'strict',
      path: '/'
    }));

    res.status(200).json({ message: 'Logged out successfully' });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
};
```

### 6. Middleware for Protected Routes

#### `/middleware/auth.js`

```javascript
import { verifyToken } from '../utils/auth';
import cookie from 'cookie';

const authMiddleware = (handler) => {
  return async (req, res) => {
    const cookies = cookie.parse(req.headers.cookie || '');
    const token = cookies.token;

    if (!token) {
      return res.status(401).json({ message: 'Authentication required' });
    }

    const user = verifyToken(token);

    if (!user) {
      return res.status(401).json({ message: 'Authentication required' });
    }

    req.user = user;
    return handler(req, res);
  };
};

export default authMiddleware;
```

### 7. Create a Protected Route

#### `/pages/protected/index.js`

```javascript
import React from 'react';
import authMiddleware from '../../middleware/auth';

const ProtectedPage = ({ user }) => {
  return (
    <div>
      <h1>Protected Page</h1>
      <p>Welcome, {user.email}</p>
    </div>
  );
};

export const getServerSideProps = authMiddleware(async (context) => {
  return {
    props: { user: context.req.user },
  };
});

export default ProtectedPage;
```

### 8. Create the Main Application File

#### `/pages/_app.js`

```javascript
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

export default MyApp;
```

### 9. Create the Home Page with Login and Registration Forms

#### `/pages/index.js`

```javascript
import { useState } from 'react';
import axios from 'axios';

const Home = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [message, setMessage] = useState('');

  const handleRegister = async () => {
    try {
      const response = await axios.post('/api/auth/register', { email, password });
      setMessage(response.data.message);
    } catch (error) {
      setMessage(error.response.data.message);
    }
  };

  const handleLogin = async () => {
    try {
      const response = await axios.post('/api/auth/login', { email, password });
      setMessage(response.data.message);
    } catch (error) {
      setMessage(error.response.data.message);
    }
  };

  return (
    <div>
      <h1>Authentication Example</h1>
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button onClick={handleRegister}>Register</button>
      <button onClick={handleLogin}>Login</button>
      {message && <p>{message}</p>}
    </div>
  );
};

export default Home;
```

### 10. Test Your Application

Now you can run your Next.js application and test the authentication system.

```bash
npm run dev
```

Navigate to [http://localhost:3000](http://localhost:3000) and test the registration and login functionality.

This setup provides a basic authentication system using JWT and cookies in a Next.js application. You can extend this example to include more features such as password reset, email verification, and social login integration.

Disclaimer: This content is generated by AI.