Project Structure
oauth-websocket-app/
│
├── server.js
├── auth/
│ └── google.js
├── middleware/
│ └── socketAuth.js
├── public/
│ └── index.html
├── .env
├── package.json
Prerequisites
- Node.js installed
- Google Developer Console project with OAuth credentials (Client ID and Secret)
- Install dependencies using:
npm install express socket.io passport passport-google-oauth20 jsonwebtoken dotenv express-session
Step 1: Environment Variables (.env)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
JWT_SECRET=your_jwt_secret
Step 2: Google OAuth Setup (auth/google.js)
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback"
}, (accessToken, refreshToken, profile, done) => {
const user = {
id: profile.id,
name: profile.displayName,
email: profile.emails[0].value
};
done(null, user);
}));
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((obj, done) => done(null, obj));
Step 3: Socket Middleware (middleware/socketAuth.js)
const jwt = require('jsonwebtoken');
module.exports = function (socket, next) {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication token required'));
}
try {
const user = jwt.verify(token, process.env.JWT_SECRET);
socket.user = user;
next();
} catch (err) {
next(new Error('Invalid token'));
}
};
Step 4: Express + Socket.IO App (server.js)
require('dotenv').config();
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const session = require('express-session');
const passport = require('passport');
const jwt = require('jsonwebtoken');
const socketAuth = require('./middleware/socketAuth');
require('./auth/google');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static('public'));
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/' }),
(req, res) => {
const token = jwt.sign(req.user, process.env.JWT_SECRET, { expiresIn: '1h' });
res.redirect(`/index.html?token=${token}`);
}
);
io.use(socketAuth);
io.on('connection', (socket) => {
console.log(`User connected: ${socket.user.name}`);
socket.on('chat message', (msg) => {
io.emit('chat message', { user: socket.user.name, message: msg });
});
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
Step 5: Frontend (public/index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>OAuth + WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<ul id="messages"></ul>
<input id="msg" autocomplete="off" />
<button onclick="send()">Send</button>
<script src="/socket.io/socket.io.js"></script>
<script>
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
if (!token) {
window.location.href = "/auth/google";
}
const socket = io({ auth: { token } });
socket.on('connect', () => {
console.log("Connected to server");
});
socket.on('chat message', (data) => {
const item = document.createElement('li');
item.textContent = `${data.user}: ${data.message}`;
document.getElementById('messages').appendChild(item);
});
function send() {
const msg = document.getElementById('msg').value;
socket.emit('chat message', msg);
document.getElementById('msg').value = '';
}
</script>
</body>
</html>
Security Recommendations
- Use HTTPS and WSS in production environments
- Avoid storing JWTs in localStorage; prefer in-memory or HttpOnly cookies
- Add input validation and rate-limiting
- Implement logout and token blacklisting if necessary
Summary
- OAuth handles authentication and generates a secure JWT
- JWT is passed to the frontend and used for WebSocket connection
- Token is verified server-side via middleware before any real-time communication is allowed