Add VKontakte OAuth provider support

This commit is contained in:
Georgiy Syralev
2026-01-01 17:20:27 +03:00
parent c294710208
commit 7a7d3151e8
6 changed files with 76 additions and 4 deletions

View File

@@ -51,4 +51,17 @@ router.get(
}
);
// VKontakte OAuth
router.get('/vkontakte', passport.authenticate('vkontakte', { scope: ['email'] }));
router.get(
'/vkontakte/callback',
passport.authenticate('vkontakte', { session: false, failureRedirect: `${FRONTEND_URL}/login?error=auth_failed` }),
(req: Request, res: Response) => {
const user = req.user as AuthenticatedUser;
const token = jwt.sign({ id: user.id }, JWT_SECRET, { expiresIn: '24h' });
res.redirect(`${FRONTEND_URL}/login?token=${token}`);
}
);
export default router;

View File

@@ -5,6 +5,7 @@ import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { Strategy as GitHubStrategy } from 'passport-github';
import { Strategy as YandexStrategy } from 'passport-yandex';
import { Strategy as VKontakteStrategy } from 'passport-vkontakte';
import { prisma } from '../../prisma/client';
const JWT_SECRET = process.env.JWT_SECRET || 'your_super_secret_key';
const OAUTH_CALLBACK_URL = process.env.OAUTH_CALLBACK_URL || 'https://api.ospab.host/api/auth';
@@ -122,6 +123,42 @@ if (process.env.YANDEX_CLIENT_ID && process.env.YANDEX_CLIENT_SECRET) {
);
}
// VKontakte OAuth
if (process.env.VK_CLIENT_ID && process.env.VK_CLIENT_SECRET) {
passport.use(
new VKontakteStrategy(
{
clientID: process.env.VK_CLIENT_ID,
clientSecret: process.env.VK_CLIENT_SECRET,
callbackURL: `${OAUTH_CALLBACK_URL}/vkontakte/callback`,
profileFields: ['email', 'city', 'bdate']
},
async (accessToken: string, refreshToken: string, params: any, profile: any, done: any) => {
try {
// VK возвращает email в params, а не в profile
const email = params.email || profile.emails?.[0]?.value;
if (!email) {
throw new Error('Email не предоставлен ВКонтакте. Убедитесь, что вы разрешили доступ к email.');
}
const oauthProfile: OAuthProfile = {
id: profile.id,
displayName: profile.displayName || `${profile.name?.givenName || ''} ${profile.name?.familyName || ''}`.trim(),
emails: [{ value: email }],
provider: 'vkontakte'
};
const user = await findOrCreateUser(oauthProfile);
return done(null, user);
} catch (error) {
return done(error as Error);
}
}
)
);
}
passport.serializeUser((user: any, done) => {
done(null, user.id);