Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement OAuth Authentication (GitHub & Google) and Email/Password Login, Registration Page and Login Page #114

Open
wants to merge 3 commits into
base: feature/webiu-2024
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 167 additions & 31 deletions webiu-server/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -1,103 +1,239 @@
// controllers/authController.js
const User = require('../models/User');
const { signToken } = require('../utils/jwt');

const User = require("../models/User");
const { signToken } = require("../utils/jwt");
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;

const { OAuth2Client } = require("google-auth-library");
const axios = require("axios");

const register = async (req, res) => {
const { name, email, password, confirmPassword, githubId } = req.body;

if (!emailRegex.test(email)) {
return res.status(400).json({
status: 'error',
message: 'Invalid email format',
status: "error",
message: "Invalid email format",
});
}

if (password !== confirmPassword) {
return res.status(400).json({
status: 'error',
message: 'Passwords do not match',
status: "error",
message: "Passwords do not match",
});
}

try {
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({
status: 'error',
message: 'User already exists',
status: "error",
message: "User already exists",
});
}

const user = new User({ name, email, password, githubId });
await user.save();

const token = signToken(user);

res.status(201).json({
status: 'success',
message: 'User registered successfully',
status: "success",
message: "User registered successfully",
data: {
user: {
id: user._id,
name: user.name,
email: user.email,
githubId: user.githubId,
},
token,
},
});
} catch (error) {
res.status(500).json({
status: 'error',
status: "error",
message: error.message,
});
}
};


const login = async (req, res) => {
const { email, password } = req.body;

try {
const user = await User.findOne({ email });

if(!user){
return res.status(401).json({
status: 'error',
message: 'User not found',
});
if (!user) {
return res.status(401).json({
status: "error",
message: "User not found",
});
}
if (!user || !(await user.matchPassword(password))) {

if (!(await user.matchPassword(password))) {
return res.status(401).json({
status: 'error',
message: 'Invalid email or password',
status: "error",
message: "Invalid email or password",
});
}


const token = signToken(user);

res.status(200).json({
status: 'success',
message: 'Login successful',
status: "success",
message: "Login successful",
data: {
user: {
id: user._id,
name: user.name,
email: user.email,
githubId:user.githubId
githubId: user.githubId,
},
token,
},
});
} catch (error) {
res.status(500).json({
status: 'error',
status: "error",
message: error.message,
});
}
};

module.exports = { register, login };

const googleLogin = async (req, res) => {
try {
const googleAuthURL = `https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=${process.env.GOOGLE_CLIENT_ID}&redirect_uri=${process.env.GOOGLE_REDIRECT_URI}&scope=email%20profile`;
res.redirect(googleAuthURL);
} catch (error) {
console.log(error);
}
}

const googleLoginCallback = async (req, res) => {
const code = req.query.code;
if (!code) {
return res.status(400).json({ message: "Authorization code missing" });
}

try {
const tokenResponse = await axios.post(
"https://oauth2.googleapis.com/token",
{
code,
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirect_uri: process.env.GOOGLE_REDIRECT_URI,
grant_type: "authorization_code",
}
);

if (tokenResponse.data.error) {
return res.status(400).json({ message: tokenResponse.data.error_description });
}

const accessToken = tokenResponse.data.access_token;
const idToken = tokenResponse.data.id_token;

const oauth2Client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET);
const ticket = await oauth2Client.verifyIdToken({
idToken: idToken,
audience: process.env.GOOGLE_CLIENT_ID,
});

const payload = ticket.getPayload();
console.log("Verified User info:", payload);

let user = await User.findOne({ email: payload.email });
if (!user) {
user = new User({
name: payload.name,
email: payload.email,
githubId: null,
googleId: payload.sub,
});
await user.save();
}
const token = signToken(user);
res.redirect(`http://localhost:4200/login?token=${token}&id=${user._id}&name=${encodeURIComponent(user.name)}&email=${encodeURIComponent(user.email)}`);
} catch (error) {
console.error("Error during Google OAuth:", error);
res.status(500).json({
message: "Error authenticating with Google",
error: error.response?.data || error.message,
});
}
};




const githubLogin = async (req, res) => {
try {
const githubAuthURL = `https://github.com/login/oauth/authorize?client_id=${process.env.GITHUB_CLIENT_ID}&scope=user:email`
res.redirect(githubAuthURL);
} catch (error) {
console.log(error);
res.status(500).json({ message: "Error during GitHub authentication" });
}
};


const githubLoginCallback = async (req, res) => {
const code = req.query.code;
if (!code) {
return res.status(400).json({ message: "Authorization code missing" });
}

try {
const tokenResponse = await axios.post(
"https://github.com/login/oauth/access_token",
null,
{
params: {
client_id: process.env.GITHUB_CLIENT_ID,
client_secret: process.env.GITHUB_CLIENT_SECRET,
code: code,
redirect_uri: process.env.GITHUB_REDIRECT_URI,
},
headers: {
accept: "application/json",
},
}
);

if (tokenResponse.data.error) {
return res.status(400).json({ message: tokenResponse.data.error_description });
}

const accessToken = tokenResponse.data.access_token;

const userResponse = await axios.get("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

const githubUser = userResponse.data;
console.log("Verified GitHub User info:", githubUser);

let user = await User.findOne({ email: githubUser.email });
if (!user) {
user = new User({
name: githubUser.name,
email: githubUser.email,
githubId: githubUser.id,
googleId: null,
});
await user.save();
}

const token = signToken(user);
res.redirect(`http://localhost:4200/login?token=${token}&id=${user._id}&name=${encodeURIComponent(user.name)}&email=${encodeURIComponent(user.email)}`);
} catch (error) {
console.error("Error during GitHub OAuth:", error);
res.status(500).json({
message: "Error authenticating with GitHub",
error: error.response?.data || error.message,
});
}
};

module.exports = { register, login, googleLogin ,googleLoginCallback,githubLogin, githubLoginCallback };
4 changes: 2 additions & 2 deletions webiu-server/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: { type: String, unique: true },
password: { type: String },
githubId: { type: String },
}, { timestamps: true });

Expand Down
Loading