temichelle13 / StudyPlanner

Study Planner Project
MIT License
1 stars 0 forks source link

Task Tile #13

Open temichelle13 opened 2 months ago

temichelle13 commented 2 months ago

What - description of what you me to do Example: Hey @autopilot implement a Google, Microsoft, and Linkedin sign-in on my website. Make changes to the front end and the back end of the application.

Why - explain why this is important Example: Easier sign-in with Google, Microsoft, and LinkedIn.

Enhancements to front end and backend will ensure ease of navigation and that the layout is logical and functional without bugs.

codeautopilot[bot] commented 2 months ago

Potential solution

To implement Google, Microsoft, and LinkedIn sign-in on your website, we need to make changes to both the front end and the back end of the application. This will involve adding sign-in buttons to the HTML, handling button clicks with JavaScript, styling the buttons with CSS, setting up OAuth routes in the backend, and configuring the necessary authentication providers.

How to implement

Frontend Changes

1. Update index.html

Add sign-in buttons for Google, Microsoft, and LinkedIn within the appropriate section of the HTML file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Study Planner</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>Study Planner</h1>
    </header>
    <main>
        <section id="schedule">
            <h2>Your Schedule</h2>
            <!-- Schedule content goes here -->
        </section>
        <section id="tasks">
            <h2>Your Tasks</h2>
            <!-- Task list and management interface goes here -->
            <div id="taskForm">
                <form>
                    <!-- Form content for adding tasks -->
                </form>
            </div>
            <div id="taskList">
                <!-- Dynamic task list will be rendered here -->
            </div>
        </section>
        <section id="auth">
            <h2>Sign In</h2>
            <button id="google-signin" class="oauth-button google-button">Sign in with Google</button>
            <button id="microsoft-signin" class="oauth-button microsoft-button">Sign in with Microsoft</button>
            <button id="linkedin-signin" class="oauth-button linkedin-button">Sign in with LinkedIn</button>
        </section>
    </main>
    <footer>
        <p>&copy; 2023 Study Planner</p>
    </footer>
    <script src="main.js"></script>
</body>
</html>

2. Update main.js

Add JavaScript code to handle click events for the new sign-in buttons and redirect users to the appropriate OAuth endpoints.

document.addEventListener('DOMContentLoaded', function() {
    const taskForm = document.getElementById('taskForm');
    const taskList = document.getElementById('taskList');

    taskForm.addEventListener('submit', function(e) {
        e.preventDefault();
        const title = document.getElementById('taskTitle').value;
        const description = document.getElementById('taskDescription').value;
        const dueDate = document.getElementById('taskDueDate').value;

        fetch('/api/tasks', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ title, description, dueDate })
        })
        .then(response => response.json())
        .then(addTaskToList)
        .catch(error => console.error('Error:', error));

        taskForm.reset();
    });

    function addTaskToList(task) {
        const div = document.createElement('div');
        div.innerHTML = `<h3>${task.title}</h3><p>${task.description}</p><p>Due: ${new Date(task.dueDate).toDateString()}</p>`;
        taskList.appendChild(div);
    }

    fetch('/api/tasks')
        .then(response => response.json())
        .then(tasks => tasks.forEach(addTaskToList))
        .catch(error => console.error('Error:', error));

    document.getElementById('google-signin').addEventListener('click', function() {
        window.location.href = '/auth/google';
    });

    document.getElementById('microsoft-signin').addEventListener('click', function() {
        window.location.href = '/auth/microsoft';
    });

    document.getElementById('linkedin-signin').addEventListener('click', function() {
        window.location.href = '/auth/linkedin';
    });
});

3. Update style.css

Add specific CSS rules to style the new sign-in buttons.

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    font-size: 16px;
}

body {
    font-family: 'Arial', sans-serif;
    background-color: #f4f4f4;
    line-height: 1.6;
    color: #333;
}

header {
    background-color: #007bff;
    color: white;
    padding: 1rem;
    text-align: center;
}

header h1 {
    margin: 0;
}

main {
    padding: 1rem;
}

section {
    background-color: white;
    margin-bottom: 1rem;
    padding: 1rem;
    border-radius: 0.5rem;
}

h2 {
    margin-bottom: 0.5rem;
}

footer {
    background-color: #f8f8f8;
    text-align: center;
    padding: 1rem;
}

@media (min-width: 768px) {
    section {
        margin: 1rem auto;
        max-width: 80%;
    }
}

.oauth-button {
    display: inline-block;
    width: 100%;
    max-width: 300px;
    padding: 10px;
    margin: 10px 0;
    border: none;
    border-radius: 5px;
    font-size: 1rem;
    color: white;
    text-align: center;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.oauth-button:hover {
    opacity: 0.9;
}

.google-button {
    background-color: #db4437;
}

.microsoft-button {
    background-color: #2b579a;
}

.linkedin-button {
    background-color: #0077b5;
}

Backend Changes

1. Update routes/userRoutes.js

Add routes to handle OAuth callbacks from Google, Microsoft, and LinkedIn.

const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const passport = require('passport');
const User = require('../models/user');
const router = express.Router();

router.post('/register', async (req, res) => {
    try {
        const user = new User(req.body);
        await user.save();
        const token = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
        res.status(201).send({ user, token });
    } catch (error) {
        res.status(400).send(error);
    }
});

router.post('/login', async (req, res) => {
    try {
        const user = await User.findByCredentials(req.body.email, req.body.password);
        const token = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
        res.send({ user, token });
    } catch (error) {
        res.status(400).send(error);
    }
});

router.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
router.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => {
    res.redirect('/');
});

router.get('/auth/microsoft', passport.authenticate('microsoft', { scope: ['user.read'] }));
router.get('/auth/microsoft/callback', passport.authenticate('microsoft', { failureRedirect: '/login' }), (req, res) => {
    res.redirect('/');
});

router.get('/auth/linkedin', passport.authenticate('linkedin', { scope: ['r_liteprofile', 'r_emailaddress'] }));
router.get('/auth/linkedin/callback', passport.authenticate('linkedin', { failureRedirect: '/login' }), (req, res) => {
    res.redirect('/');
});

module.exports = router;

2. Update auth/providers.json

Add configurations for Google, Microsoft, and LinkedIn authentication providers.

{
    "anon-user": {
        "name": "anon-user",
        "type": "anon-user",
        "disabled": false
    },
    "api-key": {
        "name": "api-key",
        "type": "api-key",
        "disabled": true
    },
    "local-userpass": {
        "name": "local-userpass",
        "type": "local-userpass",
        "config": {
            "autoConfirm": true,
            "resetFunctionName": "resetFunc",
            "runConfirmationFunction": false,
            "runResetFunction": true
        },
        "disabled": false
    },
    "google-oauth": {
        "name": "google-oauth",
        "type": "oauth2-google",
        "config": {
            "clientId": "YOUR_GOOGLE_CLIENT_ID",
            "clientSecret": "YOUR_GOOGLE_CLIENT_SECRET",
            "redirectUri": "YOUR_GOOGLE_REDIRECT_URI"
        },
        "disabled": false
    },
    "microsoft-oauth": {
        "name": "microsoft-oauth",
        "type": "oauth2-microsoft",
        "config": {
            "clientId": "YOUR_MICROSOFT_CLIENT_ID",
            "clientSecret": "YOUR_MICROSOFT_CLIENT_SECRET",
            "redirectUri": "YOUR_MICROSOFT_REDIRECT_URI"
        },
        "disabled": false
    },
    "linkedin-oauth": {
        "name": "linkedin-oauth",
        "type": "oauth2-linkedin",
        "config": {
            "clientId": "YOUR_LINKEDIN_CLIENT_ID",
            "clientSecret": "YOUR_LINKEDIN_CLIENT_SECRET",
            "redirectUri": "YOUR_LINKEDIN_REDIRECT_URI"
        },
        "disabled": false
    }
}

3. Update app.js

Include middleware for handling OAuth authentication and session management.

require('dotenv').config();
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const helmet = require('helmet');
const session = require('express-session');
const passport = require('passport');

require('./auth/passport-setup');

const app = express();
const port = process.env.PORT || 3000;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(helmet());
app.use(morgan('tiny'));

app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: true,
}));

app.use(passport.initialize());
app.use(passport.session());

process.on('uncaughtException', (error) => {
    console.error(`Uncaught Exception: ${error.message}`);
    process.exit(1);
});

process.on('unhandledRejection', (error) => {
    console.error(`Unhandled Rejection: ${error.message}`);
    process.exit(1);
});

app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

4. Create auth/passport-setup.js

Configure the Passport strategies for Google, Microsoft, and LinkedIn.

const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const MicrosoftStrategy = require('passport-microsoft').Strategy;
const LinkedInStrategy = require('passport-linkedin-oauth2').Strategy;

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: '/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
    return done(null, profile);
}));

passport.use(new MicrosoftStrategy({
    clientID: process.env.MICROSOFT_CLIENT_ID,
    clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
    callbackURL: '/auth/microsoft/callback'
}, (accessToken, refreshToken, profile, done) => {
    return done(null, profile);
}));

passport.use(new LinkedInStrategy({
    clientID: process.env.LINKEDIN_CLIENT_ID,
    clientSecret: process.env.LINKEDIN_CLIENT_SECRET,
    callbackURL: '/auth/linkedin/callback',
    scope: ['r_emailaddress', 'r_liteprofile'],
}, (accessToken, refreshToken, profile, done) => {
    return done(null, profile);
}));

passport.serializeUser((user, done) => {
    done(null, user);
});

passport.deserializeUser((obj, done) => {
    done(null, obj);
});

Additional Steps

  1. Obtain OAuth Credentials: Register your application with Google, Microsoft, and LinkedIn to obtain the client IDs and client secrets. Set up the redirect URIs for each provider.
  2. Environment Variables: Ensure you have the necessary environment variables set up for client IDs and secrets for each OAuth provider.

By following these steps, you will have implemented Google, Microsoft, and LinkedIn sign-in on your website, enhancing the user experience with easier sign-in options.

Click here to create a Pull Request with the proposed solution

Files used for this task:

Changes on index.html To address the task of adding buttons for Google, Microsoft, and LinkedIn sign-in to the `index.html` file, follow these steps: ### Steps to Modify `index.html` 1. **Add Sign-In Buttons**: Insert buttons for Google, Microsoft, and LinkedIn sign-in within the appropriate section of the HTML file. 2. **Link Buttons to OAuth Endpoints**: Ensure that these buttons are linked to the appropriate OAuth endpoints for initiating the sign-in process. ### Updated `index.html` File Here's how the updated `index.html` file should look: ```html Study Planner

Study Planner

Your Schedule

Your Tasks

Sign In

© 2023 Study Planner

``` ### Explanation - **Header and Main Sections**: These sections remain unchanged. - **New Sign-In Section**: A new section with the ID `auth` is added to include the sign-in buttons for Google, Microsoft, and LinkedIn. - **Buttons**: Each button has a unique ID to facilitate event handling in the `main.js` file. ### Next Steps - **Style the Buttons**: Update the `style.css` file to style these new buttons. - **Handle Button Clicks**: Update the `main.js` file to handle click events for these buttons and redirect users to the appropriate OAuth endpoints. This modification ensures that users can easily sign in using their Google, Microsoft, or LinkedIn accounts, enhancing the user experience.
Changes on main.js To address the task of adding JavaScript code to handle click events for the new sign-in buttons and redirect users to the appropriate OAuth endpoints, you can follow these steps: 1. **Add Event Listeners for Sign-In Buttons**: Create event listeners for the Google, Microsoft, and LinkedIn sign-in buttons. 2. **Redirect to OAuth Endpoints**: Redirect users to the respective OAuth endpoints when the buttons are clicked. Here's the updated `main.js` file with the necessary changes: ```javascript document.addEventListener('DOMContentLoaded', function() { const taskForm = document.getElementById('taskForm'); const taskList = document.getElementById('taskList'); // Event listener for form submission taskForm.addEventListener('submit', function(e) { e.preventDefault(); const title = document.getElementById('taskTitle').value; const description = document.getElementById('taskDescription').value; const dueDate = document.getElementById('taskDueDate').value; // POST request to add a new task fetch('/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ title, description, dueDate }) }) .then(response => response.json()) .then(addTaskToList) .catch(error => console.error('Error:', error)); taskForm.reset(); }); // Function to add a task to the DOM function addTaskToList(task) { const div = document.createElement('div'); div.innerHTML = `

${task.title}

${task.description}

Due: ${new Date(task.dueDate).toDateString()}

`; taskList.appendChild(div); } // Load existing tasks on page load fetch('/api/tasks') .then(response => response.json()) .then(tasks => tasks.forEach(addTaskToList)) .catch(error => console.error('Error:', error)); // Event listeners for OAuth sign-in buttons document.getElementById('googleSignIn').addEventListener('click', function() { window.location.href = '/auth/google'; }); document.getElementById('microsoftSignIn').addEventListener('click', function() { window.location.href = '/auth/microsoft'; }); document.getElementById('linkedinSignIn').addEventListener('click', function() { window.location.href = '/auth/linkedin'; }); }); ``` ### Explanation: 1. **Event Listeners for OAuth Buttons**: - Added event listeners for the Google, Microsoft, and LinkedIn sign-in buttons. - When a button is clicked, the user is redirected to the respective OAuth endpoint (`/auth/google`, `/auth/microsoft`, `/auth/linkedin`). 2. **HTML Button IDs**: - Ensure that the buttons in your `index.html` file have the IDs `googleSignIn`, `microsoftSignIn`, and `linkedinSignIn` respectively. This change will enable the front-end to handle click events for the new sign-in buttons and redirect users to the appropriate OAuth endpoints for authentication.
Changes on style.css To style the new sign-in buttons for Google, Microsoft, and LinkedIn, you can add specific CSS rules to the `style.css` file. Here is a practical proposal to achieve this: 1. **Define Button Styles**: Create a general style for the OAuth buttons to ensure consistency. 2. **Add Specific Styles**: Customize each button with the respective brand colors and logos. Here is the updated `style.css` file with the necessary styles added: ```css /* CSS reset for consistency across browsers */ * { box-sizing: border-box; margin: 0; padding: 0; } /* Root font size for easy scaling with rem units */ html { font-size: 16px; } /* Typography for body content */ body { font-family: 'Arial', sans-serif; background-color: #f4f4f4; line-height: 1.6; color: #333; } /* Header styling */ header { background-color: #007bff; color: white; padding: 1rem; text-align: center; } header h1 { margin: 0; } /* Main content area and sections */ main { padding: 1rem; } section { background-color: white; margin-bottom: 1rem; padding: 1rem; border-radius: 0.5rem; } /* Headings within sections */ h2 { margin-bottom: 0.5rem; } /* Footer styling */ footer { background-color: #f8f8f8; text-align: center; padding: 1rem; } /* Responsive design for larger screens */ @media (min-width: 768px) { section { margin: 1rem auto; max-width: 80%; } } /* OAuth Button Styles */ .oauth-button { display: inline-block; width: 100%; max-width: 300px; padding: 10px; margin: 10px 0; border: none; border-radius: 5px; font-size: 1rem; color: white; text-align: center; cursor: pointer; transition: background-color 0.3s ease; } .oauth-button:hover { opacity: 0.9; } /* Google Button */ .google-button { background-color: #db4437; } /* Microsoft Button */ .microsoft-button { background-color: #2b579a; } /* LinkedIn Button */ .linkedin-button { background-color: #0077b5; } ``` ### Explanation: - **General Button Styles**: The `.oauth-button` class provides a base style for all OAuth buttons, ensuring they have a consistent look and feel. - **Hover Effect**: The `:hover` pseudo-class is used to slightly reduce the opacity when the user hovers over the button, providing visual feedback. - **Specific Button Styles**: Each button (Google, Microsoft, LinkedIn) has its own class with the respective brand color. ### Next Steps: 1. **HTML Integration**: Ensure that the buttons in `index.html` have the appropriate classes (`google-button`, `microsoft-button`, `linkedin-button`). 2. **JavaScript Handling**: Implement the click event handlers in `main.js` to redirect users to the appropriate OAuth endpoints. This approach ensures that the sign-in buttons are visually appealing and consistent with the branding of each OAuth provider.
Changes on routes/userRoutes.js To handle OAuth callbacks from Google, Microsoft, and LinkedIn, you need to add routes in the `routes/userRoutes.js` file. These routes will handle the redirection and processing of the OAuth responses from these providers. Here's a step-by-step plan to achieve this: 1. **Install Required Packages**: Ensure you have the necessary packages installed for OAuth handling. You might need `passport`, `passport-google-oauth20`, `passport-microsoft`, and `passport-linkedin-oauth2`. 2. **Configure Passport Strategies**: Set up the strategies for Google, Microsoft, and LinkedIn in a separate configuration file or within the `app.js` file. 3. **Add Routes for OAuth**: Add routes to initiate the OAuth process and handle the callbacks. Here's how you can modify the `routes/userRoutes.js` file: ### Updated `routes/userRoutes.js` ```javascript const express = require('express'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const passport = require('passport'); const User = require('../models/user'); const router = express.Router(); // User registration with request body validation router.post('/register', async (req, res) => { // Validate request body here try { const user = new User(req.body); await user.save(); const token = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' }); res.status(201).send({ user, token }); } catch (error) { res.status(400).send(error); } }); // User login with request body validation router.post('/login', async (req, res) => { // Validate request body here try { const user = await User.findByCredentials(req.body.email, req.body.password); const token = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' }); res.send({ user, token }); } catch (error) { res.status(400).send(error); } }); // Google OAuth routes router.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] })); router.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => { // Successful authentication, redirect home. res.redirect('/'); }); // Microsoft OAuth routes router.get('/auth/microsoft', passport.authenticate('microsoft', { scope: ['user.read'] })); router.get('/auth/microsoft/callback', passport.authenticate('microsoft', { failureRedirect: '/login' }), (req, res) => { // Successful authentication, redirect home. res.redirect('/'); }); // LinkedIn OAuth routes router.get('/auth/linkedin', passport.authenticate('linkedin', { scope: ['r_liteprofile', 'r_emailaddress'] })); router.get('/auth/linkedin/callback', passport.authenticate('linkedin', { failureRedirect: '/login' }), (req, res) => { // Successful authentication, redirect home. res.redirect('/'); }); module.exports = router; ``` ### Additional Steps: 1. **Configure Passport Strategies**: In your `app.js` or a separate configuration file, configure the passport strategies for Google, Microsoft, and LinkedIn. 2. **Middleware for Session Management**: Ensure you have middleware set up for session management in `app.js`. 3. **Environment Variables**: Make sure you have the necessary environment variables set up for client IDs and secrets for each OAuth provider. By following these steps, you will have routes set up to handle OAuth authentication with Google, Microsoft, and LinkedIn.
Changes on auth/providers.json To solve the task of adding configurations for Google, Microsoft, and LinkedIn authentication providers in the `auth/providers.json` file, you need to update the JSON structure to include the necessary configurations for these providers. Here is a concrete proposal for how to modify the file: 1. **Add Google Authentication Configuration:** - Include the client ID and client secret for Google OAuth. - Set the type to `oauth2-google`. 2. **Add Microsoft Authentication Configuration:** - Include the client ID and client secret for Microsoft OAuth. - Set the type to `oauth2-microsoft`. 3. **Add LinkedIn Authentication Configuration:** - Include the client ID and client secret for LinkedIn OAuth. - Set the type to `oauth2-linkedin`. Here is the updated `auth/providers.json` file with the new configurations: ```json { "anon-user": { "name": "anon-user", "type": "anon-user", "disabled": false }, "api-key": { "name": "api-key", "type": "api-key", "disabled": true }, "local-userpass": { "name": "local-userpass", "type": "local-userpass", "config": { "autoConfirm": true, "resetFunctionName": "resetFunc", "runConfirmationFunction": false, "runResetFunction": true }, "disabled": false }, "google-oauth": { "name": "google-oauth", "type": "oauth2-google", "config": { "clientId": "YOUR_GOOGLE_CLIENT_ID", "clientSecret": "YOUR_GOOGLE_CLIENT_SECRET", "redirectUri": "YOUR_GOOGLE_REDIRECT_URI" }, "disabled": false }, "microsoft-oauth": { "name": "microsoft-oauth", "type": "oauth2-microsoft", "config": { "clientId": "YOUR_MICROSOFT_CLIENT_ID", "clientSecret": "YOUR_MICROSOFT_CLIENT_SECRET", "redirectUri": "YOUR_MICROSOFT_REDIRECT_URI" }, "disabled": false }, "linkedin-oauth": { "name": "linkedin-oauth", "type": "oauth2-linkedin", "config": { "clientId": "YOUR_LINKEDIN_CLIENT_ID", "clientSecret": "YOUR_LINKEDIN_CLIENT_SECRET", "redirectUri": "YOUR_LINKEDIN_REDIRECT_URI" }, "disabled": false } } ``` ### Steps to Implement: 1. **Obtain OAuth Credentials:** - Register your application with Google, Microsoft, and LinkedIn to obtain the client IDs and client secrets. - Set up the redirect URIs for each provider. 2. **Update the JSON File:** - Replace `YOUR_GOOGLE_CLIENT_ID`, `YOUR_GOOGLE_CLIENT_SECRET`, and `YOUR_GOOGLE_REDIRECT_URI` with the actual values from your Google OAuth setup. - Replace `YOUR_MICROSOFT_CLIENT_ID`, `YOUR_MICROSOFT_CLIENT_SECRET`, and `YOUR_MICROSOFT_REDIRECT_URI` with the actual values from your Microsoft OAuth setup. - Replace `YOUR_LINKEDIN_CLIENT_ID`, `YOUR_LINKEDIN_CLIENT_SECRET`, and `YOUR_LINKEDIN_REDIRECT_URI` with the actual values from your LinkedIn OAuth setup. 3. **Save the File:** - Save the updated `auth/providers.json` file. This configuration will enable your application to use Google, Microsoft, and LinkedIn for user authentication.
Changes on app.js To include middleware for handling OAuth authentication and session management in the `app.js` file, you can follow these steps: 1. **Install Required Packages**: Ensure you have the necessary packages installed. You will need `passport`, `passport-google-oauth20`, `passport-microsoft`, `passport-linkedin-oauth2`, and `express-session`. ```sh npm install passport passport-google-oauth20 passport-microsoft passport-linkedin-oauth2 express-session ``` 2. **Configure Passport Strategies**: Set up the configurations for Google, Microsoft, and LinkedIn authentication providers in a separate configuration file or directly in `app.js`. 3. **Initialize Passport and Session Middleware**: Add the necessary middleware to `app.js` to handle OAuth authentication and session management. Here is the updated `app.js` file with the necessary changes: ```javascript require('dotenv').config(); const express = require('express'); const cors = require('cors'); const morgan = require('morgan'); const helmet = require('helmet'); const session = require('express-session'); const passport = require('passport'); // Import Passport strategies require('./auth/passport-setup'); const app = express(); const port = process.env.PORT || 3000; // Middleware for parsing JSON and urlencoded data app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Enable CORS for all routes app.use(cors()); // Helmet for security by setting various HTTP headers app.use(helmet()); // Morgan for logging HTTP requests app.use(morgan('tiny')); // Session management app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: true, })); // Initialize Passport and use session app.use(passport.initialize()); app.use(passport.session()); // Global error handler for uncaught exceptions and unhandled promise rejections process.on('uncaughtException', (error) => { console.error(`Uncaught Exception: ${error.message}`); process.exit(1); }); process.on('unhandledRejection', (error) => { console.error(`Unhandled Rejection: ${error.message}`); }); // Starting the server app.listen(port, () => { console.log(`Server is running on port ${port}`); }); ``` ### Additional Steps 1. **Create `passport-setup.js`**: Create a new file `auth/passport-setup.js` to configure the Passport strategies for Google, Microsoft, and LinkedIn. ```javascript const passport = require('passport'); const GoogleStrategy = require('passport-google-oauth20').Strategy; const MicrosoftStrategy = require('passport-microsoft').Strategy; const LinkedInStrategy = require('passport-linkedin-oauth2').Strategy; // Configure Google Strategy passport.use(new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: '/auth/google/callback' }, (accessToken, refreshToken, profile, done) => { // Handle user profile here return done(null, profile); })); // Configure Microsoft Strategy passport.use(new MicrosoftStrategy({ clientID: process.env.MICROSOFT_CLIENT_ID, clientSecret: process.env.MICROSOFT_CLIENT_SECRET, callbackURL: '/auth/microsoft/callback' }, (accessToken, refreshToken, profile, done) => { // Handle user profile here return done(null, profile); })); // Configure LinkedIn Strategy passport.use(new LinkedInStrategy({ clientID: process.env.LINKEDIN_CLIENT_ID, clientSecret: process.env.LINKEDIN_CLIENT_SECRET, callbackURL: '/auth/linkedin/callback', scope: ['r_emailaddress', 'r_liteprofile'], }, (accessToken, refreshToken, profile, done) => { // Handle user profile here return done(null, profile); })); // Serialize user into the sessions passport.serializeUser((user, done) => { done(null, user); }); // Deserialize user from the sessions passport.deserializeUser((obj, done) => { done(null, obj); }); ``` 2. **Update Routes**: Ensure that the routes for handling OAuth callbacks are added in `routes/userRoutes.js`. By following these steps, you will have integrated OAuth authentication and session management into your `app.js` file.