Add Discord OAuth login with whitelist for user 1207017997173137481
This commit is contained in:
@@ -41,7 +41,7 @@ router.post('/login', (req, res) => {
|
||||
});
|
||||
|
||||
router.get('/me', authenticateToken, (req, res) => {
|
||||
const user = db.prepare('SELECT id, username, email, created_at FROM users WHERE id = ?').get(req.userId);
|
||||
const user = db.prepare('SELECT id, username, email, discord_id, global_name, avatar, created_at FROM users WHERE id = ?').get(req.userId);
|
||||
if (!user) return res.status(404).json({ error: 'User not found' });
|
||||
res.json({ user });
|
||||
});
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Router } from 'express';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import db from '../db.js';
|
||||
import { generateToken } from '../middleware/auth.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
const DISCORD_API = 'https://discord.com/api';
|
||||
|
||||
const DISCORD_CLIENT_ID = process.env.DISCORD_CLIENT_ID;
|
||||
const DISCORD_CLIENT_SECRET = process.env.DISCORD_CLIENT_SECRET;
|
||||
const DISCORD_REDIRECT_URI = process.env.DISCORD_REDIRECT_URI;
|
||||
|
||||
const WHITELIST = new Set([
|
||||
'1207017997173137481'
|
||||
]);
|
||||
|
||||
function getRedirectOrigin() {
|
||||
return process.env.FRONTEND_URL || 'http://localhost:3000';
|
||||
}
|
||||
|
||||
router.get('/discord', (req, res) => {
|
||||
const next = req.query.next || '/';
|
||||
const safeNext = next.startsWith('/') && !next.startsWith('//') ? next : '/';
|
||||
const params = new URLSearchParams({
|
||||
client_id: DISCORD_CLIENT_ID,
|
||||
redirect_uri: DISCORD_REDIRECT_URI,
|
||||
response_type: 'code',
|
||||
scope: 'identify',
|
||||
state: safeNext,
|
||||
});
|
||||
res.redirect(`${DISCORD_API}/oauth2/authorize?${params.toString()}`);
|
||||
});
|
||||
|
||||
router.get('/discord/callback', async (req, res) => {
|
||||
const { code, state, error } = req.query;
|
||||
|
||||
if (error) {
|
||||
return res.redirect(`${getRedirectOrigin()}/login?error=${encodeURIComponent(error)}`);
|
||||
}
|
||||
if (!code || !state) {
|
||||
return res.redirect(`${getRedirectOrigin()}/login?error=missing_code_or_state`);
|
||||
}
|
||||
|
||||
try {
|
||||
const tokenRes = await fetch(`${DISCORD_API}/oauth2/token`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
client_id: DISCORD_CLIENT_ID,
|
||||
client_secret: DISCORD_CLIENT_SECRET,
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
redirect_uri: DISCORD_REDIRECT_URI,
|
||||
}).toString(),
|
||||
});
|
||||
if (!tokenRes.ok) {
|
||||
const text = await tokenRes.text();
|
||||
throw new Error(`Discord token exchange failed: ${tokenRes.status} ${text}`);
|
||||
}
|
||||
const token = await tokenRes.json();
|
||||
|
||||
const userRes = await fetch(`${DISCORD_API}/users/@me`, {
|
||||
headers: { Authorization: `Bearer ${token.access_token}` },
|
||||
});
|
||||
if (!userRes.ok) {
|
||||
const text = await userRes.text();
|
||||
throw new Error(`Discord user fetch failed: ${userRes.status} ${text}`);
|
||||
}
|
||||
const discordUser = await userRes.json();
|
||||
|
||||
if (!WHITELIST.has(discordUser.id)) {
|
||||
return res.redirect(`${getRedirectOrigin()}/login?error=not_allowed`);
|
||||
}
|
||||
|
||||
const existing = db.prepare('SELECT id FROM users WHERE discord_id = ?').get(discordUser.id);
|
||||
let userId;
|
||||
if (existing) {
|
||||
userId = existing.id;
|
||||
db.prepare(
|
||||
"UPDATE users SET username = ?, global_name = ?, avatar = ?, updated_at = datetime('now') WHERE id = ?"
|
||||
).run(discordUser.username, discordUser.global_name, discordUser.avatar, userId);
|
||||
} else {
|
||||
userId = uuidv4();
|
||||
db.prepare(
|
||||
'INSERT INTO users (id, username, global_name, avatar, discord_id) VALUES (?, ?, ?, ?, ?)'
|
||||
).run(userId, discordUser.username, discordUser.global_name, discordUser.avatar, discordUser.id);
|
||||
}
|
||||
|
||||
const jwt = generateToken(userId);
|
||||
|
||||
const redirectTo = state.startsWith('/') ? state : '/';
|
||||
res.redirect(`${getRedirectOrigin()}${redirectTo}?token=${jwt}`);
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : 'unknown error';
|
||||
res.redirect(`${getRedirectOrigin()}/login?error=${encodeURIComponent(msg.slice(0, 200))}`);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user