LinkedIn Chat App A simple chat application where users log in with LinkedIn and send real‐time messages. The project structure:
chat-app/ ─backend/ # Node.js + Express + Socket.IO + MongoDB ─frontend/ # Static HTML + JavaScript
- Prerequisites Node.js (v14+) and npm
MongoDB Atlas (or local MongoDB)
LinkedIn Developer account with:
Product: Sign In with LinkedIn (OpenID Connect) enabled
OAuth 2.0 scopes: r_liteprofile
Authorized Redirect URL: http://localhost:5001/auth/linkedin/callback
Python 3 (to serve the frontend) or any static‐file server
-
Backend Setup
- Create .env in chat-app/backend/:
PORT=5001 MONGODB_URI="mongodb+srv://:@.mongodb.net/chat-app?retryWrites=true&w=majority" JWT_SECRET="a_very_long_random_string" LINKEDIN_CLIENT_ID=<your_linkedin_client_id> LINKEDIN_CLIENT_SECRET=<your_linkedin_client_secret> LINKEDIN_REDIRECT_URI=http://localhost:5001/auth/linkedin/callback FRONTEND_URL=http://localhost:3000
Replace <…> with your actual values.
- Install dependencies
cd chat-app/backend npm install
- Start server
npm run dev
Should print:
MongoDB connected Server listening on port 5001
Backend API Endpoints GET /auth/linkedin Redirects to LinkedIn’s OAuth consent (requests only r_liteprofile).
GET /auth/linkedin/callback?code=… Exchanges code → LinkedIn access token → fetches /v2/me → upserts user → issues JWT → redirects to http://localhost:3000/?token=.
GET /protected
Headers: Authorization: Bearer <JWT>
Response: { "message": "Hello, <FirstName>! This is a protected route." }
POST /messages
Headers: Authorization: Bearer <JWT>
Body:
{ "receiverId": "<otherUserId>", "content": "Hello!" }
Creates a message, emits newMessage via Socket.IO, returns the saved message.
GET /messages/:otherUserId
Headers: Authorization: Bearer <JWT>
Returns all messages between your user and otherUserId, sorted by timestamp.
Example cURL Requests
-
Protected Route: curl -H "Authorization: Bearer "
http://localhost:5001/protected -
Send a Message: curl -X POST http://localhost:5001/messages
-H "Authorization: Bearer "
-H "Content-Type: application/json"
-d '{"receiverId":"","content":"Hey there"}' -
Fetch Chat History curl -H "Authorization: Bearer "
http://localhost:5001/messages/ -
Frontend Setup
- Serve the static files:
cd chat-app/frontend python3 -m http.server 3000
- Open in browser (Incognito recommended):
- Click “Login with LinkedIn” → LinkedIn login/consent → back to /?token= → chat UI appears.
-
Real‐Time Messaging (Socket.IO)
After login, frontend connects:
const socket = io("http://localhost:5001", { auth: { token: jwtToken } }); socket.emit('join'); // joins room = user’s MongoDB ID
// Listen for incoming messages: socket.on('newMessage', msg => { /* display msg in chat */ });
When you send via POST /messages, the backend does io.to(receiverId).emit('newMessage', message) so the recipient sees it instantly.
- Troubleshooting “invalid_client” or no client_id:
Ensure LINKEDIN_CLIENT_ID in .env matches exactly your LinkedIn App’s Client ID.
Confirm LINKEDIN_REDIRECT_URI matches LinkedIn’s “Authorized Redirect URLs.”
“unauthorized_scope_error”:
We only request r_liteprofile. Make sure your LinkedIn App has Sign In with LinkedIn enabled and that r_liteprofile is checked under Auth → OAuth 2.0 scopes.
Chat not loading after login:
Confirm ?token= appears in the URL.
Check browser console for Socket connected: logs.
Verify frontend’s BACKEND_URL is http://localhost:5001.