IbrahimMoftah329 / Capstone

1 stars 0 forks source link

Clerk User Authentication #6

Closed IbrahimMoftah329 closed 2 weeks ago

IbrahimMoftah329 commented 1 month ago

https://dashboard.clerk.com/sign-in?redirect_url=https%3A%2F%2Fdashboard.clerk.com%2Fapps%2Fapp_2mQqzwzA1U3UMXVllJ689BMzbbo%2Finstances%2Fins_2mQqzxKUJo3RIYM1ynYytDPE4Ei

Using Clerk to handle all our User Authentication for us and use their preset templates to make things easier for us!

https://clerk.com/docs/components/overview

https://clerk.com/docs/quickstarts/react

IbrahimMoftah329 commented 1 month ago

Image Image Image Image

IbrahimMoftah329 commented 1 month ago

Install Dependencies:

npm install express mongoose @clerk/clerk-sdk-node

Define a Mongoose model to store the Clerk user ID and any additional fields you want in your MongoDB database.

import mongoose, { Schema, Document } from 'mongoose';

interface IUser extends Document {
  clerkUserId: string;
}

const UserSchema: Schema = new Schema({
  clerkUserId: { type: String, required: true, unique: true },
});

const User = mongoose.model<IUser>('User', UserSchema);

export default User;
IbrahimMoftah329 commented 1 month ago

Create Express API Route to Save User ID: Next, create an Express route that will save the Clerk user ID into MongoDB. This route will be called from your React frontend after authentication.

import express from 'express';
import { getAuth } from '@clerk/clerk-sdk-node'; // Clerk's server-side SDK
import User from './models/User'; // Mongoose User model

const router = express.Router();

router.post('/api/save-user', async (req, res) => {
  const { userId } = getAuth(req); // Get Clerk's userId from the authenticated request

  try {
    // Check if the user already exists in MongoDB
    let user = await User.findOne({ clerkUserId: userId });

    if (!user) {
      // If the user doesn't exist, create a new record
      user = new User({ clerkUserId: userId });
      await user.save();
    }

    res.status(200).json({ message: 'User saved successfully', user });
  } catch (error) {
    res.status(500).json({ message: 'Error saving user', error });
  }
});

export default router;

After authentication, Clerk provides a userId in the request. This ID is then saved in MongoDB if it’s not already present.

IbrahimMoftah329 commented 1 month ago

To ensure routes are protected, use Clerk middleware to require authentication.

import { requireAuth } from '@clerk/clerk-sdk-node'; // Clerk middleware

app.use(requireAuth());
IbrahimMoftah329 commented 1 month ago

Make sure you have the Clerk React SDK installed on the frontend.

npm install @clerk/clerk-react

Wrap the app with ClerkProvider to manage authentication.

import { ClerkProvider, RedirectToSignIn, SignedIn, SignedOut } from '@clerk/clerk-react';

const frontendApi = process.env.REACT_APP_CLERK_FRONTEND_API; // Clerk frontend API key

const App = () => (
  <ClerkProvider frontendApi={frontendApi}>
    <SignedIn>
      {/* Protected routes/components */}
      <YourMainApp />
    </SignedIn>
    <SignedOut>
      <RedirectToSignIn />
    </SignedOut>
  </ClerkProvider>
);

export default App;
IbrahimMoftah329 commented 1 month ago

Once the user is authenticated on the frontend, you can retrieve their user ID using Clerk’s useUser hook, then send it to your Express backend.

import React, { useEffect } from 'react';
import { useUser } from '@clerk/clerk-react';
import axios from 'axios';

const Dashboard = () => {
  const { user } = useUser();

  useEffect(() => {
    const saveUserToBackend = async () => {
      if (user && user.id) {
        try {
          const response = await axios.post('/api/save-user', {}, {
            headers: {
              Authorization: `Bearer ${user.session.id}`, // Send the session token
            },
          });
          console.log('User saved:', response.data);
        } catch (error) {
          console.error('Error saving user:', error);
        }
      }
    };

    saveUserToBackend();
  }, [user]);

  return <div>Welcome, {user?.fullName}!</div>;
};

export default Dashboard;

useUser() provides the authenticated user and their userId.

Once the user is authenticated, you can make a POST request to the backend route (/api/save-user), which saves the user ID to MongoDB.

IbrahimMoftah329 commented 1 month ago

Ensure that your MongoDB connection is established in your backend, usually in your server.js or app.js file.

import mongoose from 'mongoose';

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.MONGO_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log('MongoDB Connected');
  } catch (error) {
    console.error('MongoDB connection error:', error);
    process.exit(1);
  }
};

connectDB();