Twitter Authentication with React and Node.js
This guide will walk you through setting up Twitter authentication in a React application using a Node.js backend. The application will allow users to log in with their Twitter account, fetch their followers, and display them in the React app.
Prerequisites
- Node.js and npm are installed on your machine.
- Twitter Developer Account and a Twitter App set up.
- Basic knowledge of JavaScript, React, and Express.js.
- You need Basic tier Access to fetch Followers of related data, by default we only get Free tier Access.
Step 1: Setting Up the Twitter Developer Account
- Go to the Twitter Developer Portal.
- Create a new project and a new app within that project.
- Select Project → Settings → User authentication settings.
- Set the Type of App to
Web App, Automated App Or Bot
- Setup Callback URL / REDIRECT URL to
http://localhost:5000/callback
. - Set Website URL.
- Set up the OAuth 2.0 authentication settings with the callback URL:
http://localhost:5000/callback
- In your app Keys and tokens, find and copy the following credentials:
- In OAuth 2.0 Client ID and Client Secret
- Client ID and Client Secret
Step 2: Setting Up the Backend Server
- Create a new directory for your project and initialize a new Node.js project:
mkdir twitter-auth-app cd twitter-auth-app npm init -y
- Install the necessary packages:
npm install express cors dotenv axios twitter-api-s
- Create a
.env
file in the root directory and add your Twitter API credentials:
CLIENT_ID=your-twitter-api-key CLIENT_SECRET=your-twitter-api-secret-key
- Create a
server.js
file and add the following code:
// This is the Express server that will handle OAuth flow
// and will receive the access token from Twitter
// and will also be responsible for fetching the user's followers
// and will be used by the client to make requests to Twitter API
//
// The server is created to separate the logic of handling the OAuth flow
// and the logic of fetching the user's followers and to avoid
// potential security issues that can arise from mixing the two
//
// The server is also responsible for setting up CORS to allow
// the frontend to make requests to the server
const { Client, auth } = require("twitter-api-sdk");
const express = require("express");
const axios = require("axios");
// const dotenv = require("dotenv");
const cors = require("cors");
let accessToken = "";
// dotenv.config();
const app = express();
app.use(cors());
const authClient = new auth.OAuth2User({
client_id: "ZURHVmZhM0FxYm0yWDZBNTZ6c2g6MTpjaQ",
client_secret: "489DpfNasqqX5m3UnLSGyrE5968gCBB8EufXavIMKWGvxXujhY",
callback: "http://localhost:5000/callback",
scopes: ["tweet.read", "users.read"],
});
const client = new Client(authClient);
const STATE = "my-state";
app.get("/callback", async function (req, res) {
try {
const { code, state } = req.query;
if (state !== STATE) return res.status(500).send("State isn't matching");
accessToken = (await authClient.requestAccessToken(code)).token
.access_token;
console.log("AccessToken: " + JSON.stringify(accessToken));
res.send(`
<html>
<body>
<p>You have been authenticated with this platform. You can close the window now.</p>
<script>
// Pass the access token and status to the parent window
window.opener.postMessage({ token: ${JSON.stringify(
accessToken
)}, status: "Login successful" }, "*");
// Close the window after a delay
setTimeout(() => {
window.close();
}, 3000); // 3 seconds delay
</script>
</body>
</html>
`);
} catch (error) {
console.log(error);
}
});
app.get("/login", async function (req, res) {
const authUrl = authClient.generateAuthURL({
state: STATE,
code_challenge_method: "s256",
});
console.log(authUrl);
res.redirect(authUrl);
});
app.get("/tweets", async function (req, res) {
const tweets = await client.tweets.findTweetById("20");
res.send(tweets.data);
});
app.get("/revoke", async function (req, res) {
try {
const response = await authClient.revokeAccessToken();
res.send(response);
} catch (error) {
console.log(error);
}
});
app.post("/followers", async (req, res) => {
try {
// const { accessToken } = req.body;
const userResponse = await axios.get("https://api.twitter.com/2/users/me", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
});
const userId = userResponse.data.data.id;
console.log("User ID: " + userId);
const response = await axios.get(
`https://api.twitter.com/2/users/${userId}/followers`,
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
}
);
res.send(response.data.data);
} catch (error) {
console.error("Error fetching followers:", error);
res.status(500).send("Failed to fetch followers");
}
});
app.use(
cors({
origin: "https://localhost:3000",
})
);
app.listen(5000, () => {
console.log(`Go here to login: http://localhost:5000/login`);
});
Step 3: Setting Up the React Client
- Create a new React application in the
twitter-auth-app
directory:
npx create-react-app client cd client
- Install axios for making HTTP requests:
npm install axiosUpdate src/App.js with the following code:
Create a `server.js` file and add the following code:
'use client'
import axios from "axios";
import CustomCard from "../Components/Card";
import styles from "../page.module.css";
import { useEffect, useState } from "react";
export default function page() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [userID, setUserID] = useState('');
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [picture, setPicture] = useState('');
const [accessToken, setAccessToken] = useState(null);
const [loginStatus, setLoginStatus] = useState(null);
const [followers, setFollowers] = useState([]);
useEffect(() => {
const handleMessage = (event) => {
if (event.origin !== "http://localhost:5000") return;
const { token, status } = event.data;
if (token) {
setAccessToken(token);
setLoginStatus(status);
}
};
window.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
};
}, []);
const handleLogin = async () => {
try {
// const response = await axios.get('http://localhost:5000/login');
// const authUrl = response.data.url;
window.open("http://localhost:5000/login", '_blank', 'width=600,height=700');
} catch (error) {
console.error('Error initiating Twitter login', error);
}
};
const handleLogout = async () => {
};
const handleFetchEmail = async () => {
};
const handleFetchFollowers = async () => {
try {
const response = await axios.post("http://localhost:5000/followers", {
accessToken,
});
console.log(response.data)
} catch (error) {
console.error("Error fetching followers", error);
}
};
const handleFetchPosts = async () => {
};
const handleFetchPermissions = async () => {
};
return (
<main className={styles.main}>
<CustomCard >
<div className={styles.btnCont}>
<button className={styles.btn} onClick={handleLogin}>Login</button>
<button className={styles.btn} onClick={handleFetchFollowers}>Fetch Followers</button>
{/* <button className={styles.btn} onClick={handleLogout}>Logout</button>
<button className={styles.btn} onClick={handleFetchEmail}>Fetch Email</button>
<button className={styles.btn} onClick={handleFetchPosts}>Fetch Posts</button>
<button className={styles.btn} onClick={handleFetchPermissions}>User Permission</button> */}
</div>
</CustomCard>
</main>
);
}
Step 4: Running the Application
- Start the Backend Server:
cd twitter-auth-app node server.js
- Start the React Client: Open a new terminal window and run:
cd twitter-auth-app/client npm start
Conclusion
You have successfully set up Twitter authentication in a React application using a Node.js backend. Users can log in with their Twitter account, fetch followers, and display them in the React app. This setup provides a solid foundation for further enhancements, such as additional Twitter API interactions or improved user interface elements.