Some checks failed
Deploy to production / deploy (push) Failing after 49s
- Created OAuth credentials setup guide for Google, Microsoft, Keycloak, ORY, and ZITADEL. - Added migration for oauth_identity table to store OAuth identities linked to users. - Implemented OAuthIdentity model for managing OAuth identities in the database. - Developed oauthService to handle OAuth login, user creation, and identity linking. - Created OAuthCallbackView and OAuthUserCallbackView components for handling OAuth responses in the frontend. - Added error handling and user feedback during the OAuth process.
203 lines
7.3 KiB
JavaScript
203 lines
7.3 KiB
JavaScript
import * as userService from '../services/authService.js';
|
|
import * as oauthService from '../services/oauthService.js';
|
|
|
|
class AuthController {
|
|
constructor() {
|
|
this.register = this.register.bind(this);
|
|
this.login = this.login.bind(this);
|
|
this.forgotPassword = this.forgotPassword.bind(this);
|
|
this.activateAccount = this.activateAccount.bind(this);
|
|
this.logout = this.logout.bind(this);
|
|
this.oauthProviders = this.oauthProviders.bind(this);
|
|
this.oauthStart = this.oauthStart.bind(this);
|
|
this.oauthExchange = this.oauthExchange.bind(this);
|
|
this.oauthUserIdentities = this.oauthUserIdentities.bind(this);
|
|
this.oauthUserStart = this.oauthUserStart.bind(this);
|
|
this.oauthUserExchange = this.oauthUserExchange.bind(this);
|
|
this.oauthUserRemove = this.oauthUserRemove.bind(this);
|
|
}
|
|
|
|
async register(req, res) {
|
|
const { email, username, password, language } = req.body;
|
|
try {
|
|
const result = await userService.registerUser({ email, username, password, language });
|
|
res.status(201).json(result);
|
|
} catch (error) {
|
|
console.log(error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async login(req, res) {
|
|
const { username, password } = req.body;
|
|
try {
|
|
const result = await userService.loginUser({ username, password });
|
|
console.log('User logged in successfully', result);
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
if (error.message === 'credentialsinvalid') {
|
|
res.status(404).json({ error: error.message });
|
|
} else if (error.message === 'userblocked') {
|
|
res.status(403).json({ error: error.message });
|
|
} else {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
}
|
|
|
|
async logout(req, res) {
|
|
const { userid: hashedUserId } = req.headers;
|
|
await userService.logoutUser(hashedUserId);
|
|
res.status(200).json({ result: 'loggedout' });
|
|
}
|
|
|
|
async oauthProviders(req, res) {
|
|
try {
|
|
const providers = await oauthService.getOAuthProviders();
|
|
res.status(200).json({ providers });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthStart(req, res) {
|
|
const { provider } = req.params;
|
|
try {
|
|
const redirectTo = await oauthService.startOAuthLogin({ providerSlug: provider });
|
|
res.redirect(302, redirectTo.toString());
|
|
} catch (error) {
|
|
const status = error.message === 'providernotconfigured' ? 503 : 500;
|
|
res.status(status).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthExchange(req, res) {
|
|
const { code, state } = req.body;
|
|
try {
|
|
const result = await oauthService.exchangeOAuthLogin({ code, state });
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
const knownErrors = new Set([
|
|
'oauthcodemissing',
|
|
'oauthstatemissing',
|
|
'oauthsubjectmissing',
|
|
'providernotconfigured',
|
|
'oauthidentityconflict'
|
|
]);
|
|
const status = knownErrors.has(error.message) ? 400 : 500;
|
|
res.status(status).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthUserIdentities(req, res) {
|
|
const { userid: hashedUserId } = req.headers;
|
|
try {
|
|
const User = (await import('../models/community/user.js')).default;
|
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'usernotfound' });
|
|
}
|
|
|
|
const identities = await oauthService.getUserOAuthIdentities(user.id);
|
|
res.status(200).json({ identities });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthUserStart(req, res) {
|
|
const { userid: hashedUserId } = req.headers;
|
|
const { provider } = req.params;
|
|
try {
|
|
const User = (await import('../models/community/user.js')).default;
|
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'usernotfound' });
|
|
}
|
|
|
|
const redirectTo = await oauthService.startOAuthLoginForUser({
|
|
userId: user.id,
|
|
providerSlug: provider
|
|
});
|
|
res.redirect(302, redirectTo.toString());
|
|
} catch (error) {
|
|
const status = error.message === 'providernotconfigured' ? 503 : 500;
|
|
res.status(status).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthUserExchange(req, res) {
|
|
const { userid: hashedUserId } = req.headers;
|
|
const { code, state } = req.body;
|
|
try {
|
|
const User = (await import('../models/community/user.js')).default;
|
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'usernotfound' });
|
|
}
|
|
|
|
const result = await oauthService.exchangeOAuthLoginForUser({
|
|
userId: user.id,
|
|
code,
|
|
state
|
|
});
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
const knownErrors = new Set([
|
|
'oauthcodemissing',
|
|
'oauthstatemissing',
|
|
'oauthsubjectmissing',
|
|
'providernotconfigured',
|
|
'oauthuseridmismatch',
|
|
'oauthidentityalreadylinked'
|
|
]);
|
|
const status = knownErrors.has(error.message) ? 400 : 500;
|
|
res.status(status).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async oauthUserRemove(req, res) {
|
|
const { userid: hashedUserId } = req.headers;
|
|
const { identityId } = req.params;
|
|
try {
|
|
const User = (await import('../models/community/user.js')).default;
|
|
const user = await User.findOne({ where: { hashedId: hashedUserId } });
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'usernotfound' });
|
|
}
|
|
|
|
const result = await oauthService.removeOAuthIdentity({
|
|
userId: user.id,
|
|
identityId: parseInt(identityId, 10)
|
|
});
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
const status = error.message === 'forbidden' ? 403 : 500;
|
|
res.status(status).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
|
|
async forgotPassword(req, res) {
|
|
const { email } = req.body;
|
|
try {
|
|
const result = await userService.handleForgotPassword({ email });
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
|
|
async activateAccount(req, res) {
|
|
const { token } = req.body;
|
|
try {
|
|
const result = await userService.activateUserAccount({ token });
|
|
res.status(200).json(result);
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
}
|
|
}
|
|
|
|
export default AuthController;
|