Merge pull request #6 from OlaketalAmigo/github_oauth

GitHub oauth
This commit is contained in:
H3XploR
2026-01-16 16:56:41 +01:00
committed by GitHub
5 changed files with 120 additions and 13 deletions
+2 -1
View File
@@ -23,4 +23,5 @@ Gestion de friendship dans POSTGRESQL:
Ressource:
https://www.postgresql.org/docs/
https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps
https://docs.github.com/fr/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app
+35 -3
View File
@@ -59,6 +59,16 @@ async function createTables()
FOREIGN KEY (id_user1) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (id_user2) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS oauth_clients (
id SERIAL PRIMARY KEY,
provider VARCHAR(50) NOT NULL,
client_id VARCHAR(200) NOT NULL,
client_secret TEXT,
redirect_uri VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(provider, client_id)
);
`);
console.log('Tables created!');
}
@@ -73,9 +83,31 @@ async function query(text, params)
return (pool.query(text, params));
}
module.exports =
async function ensureOauthClient(provider, client_id, client_secret, redirect_uri)
{
try
{
const res = await pool.query(
`SELECT id FROM oauth_clients WHERE provider = $1 AND client_id = $2`, [provider, client_id]
);
if (res.rows.length > 0)
return res.rows[0];
const insert = await pool.query(
`INSERT INTO oauth_clients (provider, client_id, client_secret, redirect_uri) VALUES ($1, $2, $3, $4) RETURNING id`,
[provider, client_id, client_secret, redirect_uri]
);
return insert.rows[0];
}
catch (err)
{
console.error('Error ensuring oauth client:', err);
throw err;
}
}
module.exports = {
waitForDb,
createTables,
query
};
query,
ensureOauthClient
};
+10 -3
View File
@@ -4,13 +4,13 @@ const cors = require('cors');
const {Server} = require('socket.io');
const authRouter = require('./routes/auth');
const chatRouter = require('./routes/global_chat');
const {waitForDb, createTables} = require('./db');
const {waitForDb, createTables, ensureOauthClient} = require('./db');
const setupSocketIO = require('./services/socket');
const app = express();
const server = http.createServer(app);
const io = new Server(server,
{
{
cors:
{
origin: "*",
@@ -28,6 +28,13 @@ async function startServer()
await waitForDb();
await createTables();
// Ensure GitHub OAuth client is registered in DB
try {
await ensureOauthClient('github', process.env.GITHUB_CLIENT_ID, process.env.GITHUB_CLIENT_SECRET, process.env.GITHUB_CALLBACK_URL || process.env.GITHUB_REDIRECT_URI);
} catch (e) {
console.warn('OAuth client might already exist or failed to register:', e.message);
}
app.use('/api/auth', authRouter);
app.use('/api/global_chat', chatRouter);
app.get('/api', (req, res) => res.send('Backend running'));
@@ -38,4 +45,4 @@ async function startServer()
});
}
startServer();
startServer();
+56 -2
View File
@@ -2,6 +2,9 @@ const express = require('express');
const router = express.Router();
const authService = require('../services/auth');
const fetch = require('node-fetch');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const {query} = require('../db');
router.post('/register', async(req, res) =>
{
@@ -24,10 +27,61 @@ router.post('/login', async(req, res) =>
router.get('/github', (req, res) => {
const githubAuthUrl = `https://github.com/login/oauth/authorize?` +
`client_id=${process.env.GITHUB_CLIENT_ID}&` +
`redirect_uri=${encodeURIComponent(process.env.GITHUB_REDIRECT_URI)}&` +
`redirect_uri=${encodeURIComponent(process.env.GITHUB_CALLBACK_URL || process.env.GITHUB_REDIRECT_URI)}&` +
`scope=user:email`;
res.redirect(githubAuthUrl);
});
module.exports = router;
router.get('/github/callback', async (req, res) => {
const code = req.query.code;
if (!code) {
return res.status(400).send('Missing code');
}
try {
const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.GITHUB_CLIENT_ID,
client_secret: process.env.GITHUB_CLIENT_SECRET,
code: code
})
});
const tokenData = await tokenResponse.json();
const accessToken = tokenData.access_token;
if (!accessToken) throw new Error('No access token');
const userResponse = await fetch('https://api.github.com/user', {
headers: { 'Authorization': `Bearer ${accessToken}`, 'User-Agent': 'Transcendence' }
});
const ghUser = await userResponse.json();
const ghUsername = ghUser.login || `github_${ghUser.id}`;
let result = await query(`SELECT id FROM users WHERE username = $1`, [ghUsername]);
let userId;
if (result.rows.length > 0) {
userId = result.rows[0].id;
} else {
const crypto = require('crypto');
const randomPwd = crypto.randomBytes(16).toString('hex');
const passwordHash = await bcrypt.hash(randomPwd, 10);
await query(`INSERT INTO users (username, password_hash) VALUES ($1, $2)`, [ghUsername, passwordHash]);
const inserted = await query(`SELECT id FROM users WHERE username = $1`, [ghUsername]);
userId = inserted.rows[0].id;
}
// Issue JWT
const token = jwt.sign({ userId: userId, username: ghUsername }, process.env.JWT_SECRET, { expiresIn: '1h' });
// Send token to opener window and close popup
res.send(`<!doctype html><html><body><script>window.opener && window.opener.postMessage({token: '${token}'}, '*'); window.close();</script></body></html>`);
} catch (err) {
console.error(err);
res.status(500).send('GitHub OAuth error');
}
});
module.exports = router;
+17 -4
View File
@@ -40,12 +40,25 @@ export class LoginWindow extends fenetre {
this.githubBtn.style.backgroundColor = "#24292e";
this.githubBtn.style.color = "white";
this.githubBtn.onclick = () => {
window.location.href = "/api/auth/github";
// Ouvre le OAuth GitHub dans une popup et reçoit le token via postMessage
const w = 600;
const h = 700;
const left = (screen.width - w) / 2;
const top = (screen.height - h) / 2;
const popup = window.open('/api/auth/github', 'githubOAuth', `width=${w},height=${h},left=${left},top=${top}`);
const listener = (ev) => {
if (ev.data && ev.data.token) {
localStorage.setItem('auth_token', ev.data.token);
this.message.innerText = 'Connexion GitHub réussie ! Bienvenue.';
this.message.style.color = '#3cff01';
window.removeEventListener('message', listener);
if (popup) popup.close();
}
};
window.addEventListener('message', listener, {once: true});
};
this.body.appendChild(this.githubBtn);
this.checkIfAlreadyLoggedIn(); //verifie si l'utilisateur est connecté au démarrage
}
@@ -152,4 +165,4 @@ export class LoginWindow extends fenetre {
this.switch.innerText = "S'inscrire";
}
}
}
}