I am creating OAuth2 for my application by which the people who are redirected to the server by clickking it will get the verified role. Can somebody please help me on how i can add it in my script. Right now I am using the script given below:
const express = require('express');
const { port } = require('./config.json');
const app = express();
app.get('/', (request, response) => {
console.log(`The access code is: ${request.query.code}`)
;
return response.sendFile('index.html', { root: '.' });
});
app.listen(port, () => console.log(`App listening at http://localhost:${port}`));
and from the index file they get redirected to the server here's the index.html script:
<script>
window.location.href = "https://discord.gg/DhsYQ3u4jj";
</script>
<div id="info">Congrats! You have been successfully connected to Discord.</div>
<a id="login" style="display: none;" href="https://discord.gg/jkBJarBY">Click here to Join Akudo's official Discord!</a>
<script>
window.onload = () => {
const fragment = new URLSearchParams(window.location.hash.slice(1));
const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')];
if (!accessToken) {
return (document.getElementById('login').style.display = 'block');
}
fetch('https://discord.com/api/users/#me', {
headers: {
authorization: `${tokenType} ${accessToken}`,
},
})
.then(result => result.json())
.then(response => {
const { username, discriminator } = response;
document.getElementById('info').innerText += ` ${username}#${discriminator}`;
})
.catch(console.error);
};
</script>
Related
I would like to scrape multiple websites using NodeJS, Express, Cheerio and Axios.
I'm able now to scrape 1 website and display the information to the HTML.
But when I try to scrape multiple websites looking for the same element, it doesn't go through the forEach (stops after 1 cycle). Notice my loop which doesn't work correctly:
urls.forEach(url => {
2 files that are the most important:
index.js
const PORT = 8000
const axios = require('axios')
const cheerio = require('cheerio')
const express = require('express')
const app = express()
const cors = require('cors')
app.use(cors())
const urls = ['https://www.google.nl','https://www.google.de']
// const url = 'https://www.heineken.com/nl/nl/'
app.get('/', function(req, res){
res.json('Robin')
})
urls.forEach(url => {
app.get('/results', (req, res) => {
axios(url)
.then(response => {
const html = response.data
const $ = cheerio.load(html)
const articles = []
$('script', html).each(function(){
const link = $(this).get()[0].namespace
if (link !== undefined) {
if (link.indexOf('w3.org') > -1) {
articles.push({
link
})
}
}
})
res.json(articles)
}).catch(err => console.log(err))
})
})
app.listen(PORT, () => console.log('server running on PORT ${PORT}'))
App.js:
const root = document.querySelector('#root')
fetch('http://localhost:8000/results')
.then(response => {return response.json()})
.then(data => {
console.log(data)
data.forEach(article => {
const title = `<h3>` + article.link + `</h3>`
root.insertAdjacentHTML("beforeend", title)
})
})
You're registering multiple route handlers for the same route. Express will only route requests to the first one. Move your URL loop inside app.get("/results", ...)...
app.get("/results", async (req, res, next) => {
try {
res.json(
(
await Promise.all(
urls.map(async (url) => {
const { data } = await axios(url);
const $ = cheerio.load(data);
const articles = [];
$("script", html).each(function () {
const link = $(this).get()[0].namespace;
if (link !== undefined) {
if (link.indexOf("w3.org") > -1) {
articles.push({
link,
});
}
}
});
return articles;
})
)
).flat() // un-nest each array of articles
);
} catch (err) {
console.error(err);
next(err); // make sure Express responds with an error
}
});
I'm following this link for the tutorial (via twilio.) and have followed all the
required steps but when I run the localhost and input a number, I get no text message, nor does the window for verification open. It just stays at the same page of "enter your phone number".
Here's my HTML code
<!DOCTYPE HTML>
<HTML>
<head>
<title>Verify SMS Demo</title>
<style>
#verify-form,
#response-text {
display: none;
}
</style>
</head>
<body>
<form id="phone-form">
<h2>Enter your phone number with country code:</h2>
<input type="tel" id="phone-number-input" placeholder="15551235555" />
<input id="phone-submit" type="submit" />
</form>
<form id="verify-form">
<h2>Enter your verification code:</h2>
<input type="number" id="otp-input" placeholder="e.g. 123456" />
<input id="verify-submit" type="submit" />
</form>
<div id="response-text"></div>
</body>
<script type="text/javascript" src = "script.js"></script>
</html>`
And here's my code for script.js:
const phoneForm = document.getElementById('phone-form');
const verifyForm = document.getElementById('verify-form');
const responseText = document.getElementById('response-text');
let phoneNumber;
phoneForm.addEventListener('submit', async e => {
e.preventDefault();
phoneNumber = document.getElementById('phone-number-input').value;
const response = await fetch('/send-notification', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({phoneNumber : phoneNumber })
}).catch(e => console.log(e));
if (response.ok) {
phoneForm.style.display = 'none';
verifyForm.style.display = 'block';
}
});
verifyForm.addEventListener('submit', async e => {
e.preventDefault();
const otp = document.getElementById('otp-input').value;
const data = {
phoneNumber: phoneNumber,
otp: top
};
const response = await fetch('/verify-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify(data)
}).catch(e => console.log(e));
const check = await response.json();
const text = response.ok ? check.status : response.statusText;
responseText.innerHTML = text;
verifyForm.style.display = 'none';
responseText.style.display = 'block';
});
EDIT Here is my index.js file:
const express = require('express');
const path = require('path');
require('dotenv').config();
const client = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
const app = express();
const port = process.env.PORT || 3000;
app.use(express.static(__dirname + '/public'));
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '/views/index.html'));
});
app.post('/send-verification', async (req, res) => {
client.verify.services(verify)
.verifications
.create({to: `+${req.body.phoneNumber}`, channel: 'sms'})
.then(verification => console.log(verification.status))
.catch(e => {
console.log(e)
res.status(500).send(e);
});
res.sendStatus(200);
});
app.post('/verify-otp', async (req, res) => {
const check = await client.verify.services(verify)
.verificationChecks
.create({to: `+${req.body.phoneNumber}`, code: req.body.otp})
.catch(e => {
console.log(e)
res.status(500).send(e);
});
res.status(200).send(check);
});
app.listen(port);
console.log('Server started at http://localhost:' + port);
Your front-end is making a request to /send-notification but your application end point is at /send-verification.
Update your front-end code to:
const response = await fetch('/send-verification', {
and you should be good to go.
Edit
Now, in the server you are getting the error:
sh-3.2$ node index.js Server started at localhost:3000
/Users/username/Downloads/keep_out-3/verify-sms-express/index.js:17
client.verify.services(verify)
^ ReferenceError: verify is not defined
You have the line:
const check = await client.verify.services(verify)
In the blog post this is:
client.verify.services(process.env.VERIFY_SERVICE_SID);
So, you have replaced the verify service sid with a non-existant verify variable. Go back and make sure you have VERIFY_SERVICE_SID set in your .env file and then change the code back to the original, and then you should be good to go!
Whenever I make an axios call to an the '/login' endpoint, I keep getting the following error printed in my browser console. I've included the server.js file and the file from where I'm making the call for your reference.
Dependencies installed in the client folder: axios, react, react-dom, react-router-dom
Dependencies installed in the server folder: cors, express, node, spotify-web-api-node
GET http://localhost:3001/login net::ERR_EMPTY_RESPONSE
index.js file
import axios from 'axios'
const Profile = () => {
const login = () => {
console.log("testing login function - client")
axios.get("http://localhost:3001/login")
.then(() => {
console.log("success")
})
.catch(() => {
console.log("error")
})
}
return (
<div className="profile">
.
.
.
<div className="button">
<button onClick={() => login()} className="btn">Log In</button>
</div>
</div>
</div>
)
}
export default Profile
server.js file
const SpotifyWebAPINode = require('spotify-web-api-node')
const express = require('express')
const cors = require("cors")
const app = express()
app.use(cors)
// This file is copied from: https://github.com/thelinmichael/spotify-web-api-node/blob/master/examples/tutorial/00-get-access-token.js
const scopes = [
'user-top-read',
'user-library-read',
'playlist-read-private',
'playlist-read-collaborative',
'playlist-modify-public',
'playlist-modify-private',
]
// credentials are optional
var spotifyApi = new SpotifyWebAPINode({
clientId: 'XXX',
clientSecret: 'XXX',
redirectUri: 'http://localhost:3001/callback',
})
app.get('/login', (req, res) => {
console.log("testing login endpoint - server")
res.redirect(spotifyApi.createAuthorizeURL(scopes))
})
app.get('/callback', (req, res) => {
const error = req.query.error
const code = req.query.code
const state = req.query.state
if (error) {
console.error('Callback Error:', error)
res.send(`Callback Error: ${error}`)
return
}
spotifyApi
.authorizationCodeGrant(code)
.then((data) => {
const access_token = data.body['access_token']
const refresh_token = data.body['refresh_token']
const expires_in = data.body['expires_in']
spotifyApi.setAccessToken(access_token)
spotifyApi.setRefreshToken(refresh_token)
console.log('access_token:', access_token)
console.log('refresh_token:', refresh_token)
console.log(
`Sucessfully retreived access token. Expires in ${expires_in} s.`,
)
res.send('Success! You can now close the window.')
setInterval(async () => {
const data = await spotifyApi.refreshAccessToken()
const access_token = data.body['access_token']
console.log('The access token has been refreshed!')
console.log('access_token:', access_token)
spotifyApi.setAccessToken(access_token)
}, (expires_in / 2) * 1000)
})
.catch((error) => {
console.error('Error getting Tokens:', error)
res.send(`Error getting Tokens: ${error}`)
})
})
app.listen(3001, () => {
console.log('Server live on port 3001')
})
When deploying a twitter streaming app which is working well on my local environment, to a live webserver, I'm getting a 404 error related to socket.io. I saw that there a numerous similar questions here already but did not find an answer solving the problem I'm facing.
Problem description:
Once I start server.js, it correctly logs 'Listening on Port 3000' to the console (terminal)
However, the message "Client connected..." is not triggered
In the browser console, I'm seeing the error message "GET https://exampledomain.com/socket.io/?EIO................(etc) - 404 - XHR failed loading"
I have already tried the following changes without success, amongst other things:
Changed the server.js code from const http = require('http') to const https = require('https')
Changed the port from 3000 to others to rule out a certain port # is already in use elsewhere, e.g. 8001 or 3333
The full server code (in public_html/server/server.js):
const http = require('http')
const path = require('path')
const express = require('express')
const socketIo = require('socket.io')
const needle = require('needle')
const config = require('dotenv').config()
const TWITTER_BEARER_TOKEN = 'xxxxxx'
const PORT = process.env.PORT || 3000
const app = express()
const server = http.createServer(app)
const io = socketIo(server)
console.log(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
// /usr/www/users/antick/public_html/client/index.html
})
const rulesURL = 'https://api.twitter.com/2/tweets/search/stream/rules'
const streamURL = 'https://api.twitter.com/2/tweets/search/stream?tweet.fields=public_metrics&expansions=author_id,attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width&user.fields=profile_image_url'
const rules = [{ value: 'corruption' }]
// Get stream rules
async function getRules() {
const response = await needle('get', rulesURL, {
headers: {
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
// Set stream rules
async function setRules() {
const data = {
add: rules
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
// Delete stream rules
async function deleteRules(rules) {
if (!Array.isArray(rules.data)) {
return null
}
const ids = rules.data.map((rule) => rule.id)
const data = {
delete: {
ids: ids
}
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
return response.body
}
function streamTweets(socket) {
const stream = needle.get(streamURL, {
headers: {
Authorization: `Bearer ${TWITTER_BEARER_TOKEN}`
}
})
stream.on('data', (data) => {
try {
const json = JSON.parse(data)
console.log(json)
socket.emit('tweet', json)
} catch (error) {}
})
}
io.on('connection', async () => {
console.log('Client connected...')
let currentRules
try {
// Get all stream rules
currentRules = await getRules()
// Delete all stream rules
await deleteRules(currentRules)
// Set rules based on array above (Rules)
await setRules()
} catch (error) {
console.error(error)
process.exit(1)
}
streamTweets(io)
})
server.listen(PORT, () => console.log(`Listening on Port ${PORT}`))
My client code - excerpt only (in public_html/client/index.html):
<div class="container">
<div id="tweetStream"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.js" integrity="sha512-iZIBSs+gDyTH0ZhUem9eQ1t4DcEn2B9lHxfRMeGQhyNdSUz+rb+5A3ummX6DQTOIs1XK0gOteOg/LPtSo9VJ+w==" crossorigin="anonymous" referrerpolicy="no-referrer">
</script>
<script>
const tweetStream = document.getElementById('tweetStream')
const socket = io()
//const socket = io.connect('https://www.exampledomain.com:3000/');
const tweets = []
socket.on('connect', () => {
console.log('Connected to server...')
})
socket.on('tweet', (tweet) => {
// (code continues here)
My suspicion is that is has to do something with the paths used in these two locations:
in server/server.js:
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'public_html/client', 'index.html'))
// resolves to: /usr/www/users/antick/public_html/client/index.html
})
in client/index.html: const socket = io() //
What else could possibly cause the error described above? I am grateful for any help. Thanks!
With help from a pro developer I was finally able to fix the problem so I would like to post the solution.
The two main points were:
Open Port # 3000 to any IPs (as it is unknown from which IP address a client would access the site)
Install pm2 in addition to node in order to constantly stream the tweets
The full resulting code looks as follows:
A) Server (index.js):
const http = require('http')
const path = require('path')
const express = require('express')
const socketIo = require('socket.io')
const needle = require('needle')
const config = require('dotenv').config()
const TOKEN = process.env.TWITTER_BEARER_TOKEN
const PORT = process.env.PORT || 3000
const app = express()
const server = http.createServer(app)
const io = socketIo(server)
app.get('/', (req, res) => {
res.sendFile(path.resolve(__dirname, '../', 'client', 'index.html'))
})
const rulesURL = 'https://api.twitter.com/2/tweets/search/stream/rules'
const streamURL = 'https://api.twitter.com/2/tweets/search/stream?tweet.fields=public_metrics&expansions=author_id,attachments.media_keys&media.fields=duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width&user.fields=profile_image_url'
const rules = [{ value: 'searchterm' }]
// Get stream rules
async function getRules() {
const response = await needle('get', rulesURL, {
headers: {
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
// Set stream rules
async function setRules() {
const data = {
add: rules
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
// Delete stream rules
async function deleteRules(rules) {
if(!Array.isArray(rules.data)) {
return null
}
const ids = rules.data.map((rule) => rule.id)
const data = {
delete: {
ids: ids
}
}
const response = await needle('post', rulesURL, data, {
headers: {
'content-type': 'application/json',
Authorization: `Bearer ${TOKEN}`
}
})
return response.body
}
function streamTweets (socket) {
const stream = needle.get(streamURL, {
headers: {
Authorization: `Bearer ${TOKEN}`
}
})
stream.on('data', (data) => {
try {
const json = JSON.parse(data)
console.log(json)
console.log(json.includes.media[0])
socket.emit('tweet', json)
} catch (error) {}
})
}
io.on('connection', async () => {
console.log('Client connected...')
let currentRules
try {
// Get all stream rules
currentRules = await getRules()
// Delete all stream rules
await deleteRules(currentRules)
// Set rules based on array above (Rules)
await setRules()
} catch (error) {
console.error(error)
process.exit(1)
}
streamTweets(io)
})
server.listen(PORT, () => console.log(`Listening on Port ${PORT}`))
B) Client (index.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"
integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA=="
crossorigin="anonymous"
/>
<title>Real-Time Tweet Stream</title>
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
<div class="container">
Real-Time Tweet Stream
</div>
</nav>
<div class="container">
<div id="tweetStream"></div>
</div>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js"
integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ=="
crossorigin="anonymous"
></script>
<script>
const tweetStream = document.getElementById('tweetStream')
const socket = io('IP.IP.IP.IP:3000' , { transports : ['websocket'] } ) // webserver IP address
const tweets = []
socket.on('connect', () => {
console.log('Connected to server...')
})
socket.on('tweet', (tweet) => {
// console.log(tweet)
const tweetData = {
id: tweet.data.id,
text: tweet.data.text,
username: `#${tweet.includes.users[0].username}`,
}
const tweetEl = document.createElement('div')
tweetEl.className = 'card my-4'
tweetEl.innerHTML = `
<div class="card-body">
<h5 class="card-title">${tweetData.text}</h5>
<h6 class="card-subtitle mb-2 text-muted">${tweetData.username}</h6>
<a class="btn btn-primary mt-3" href="https://twitter.com/${tweetData.username}/status/${tweetData.id}">
<i class="fab fa-twitter"></i> Go To Tweet
</a>
</div>
`
tweetStream.appendChild(tweetEl)
})
</script>
</body>
</html>
Following the example from OAuth2WebServer from google I'm trying to set up an authentication flow from an express app using the HTTP/REST method they have but with every request I am returned with an error
I went through Google OAuth “invalid_grant” nightmare — and how to fix it but unfortunately it did not help.
{
error: "unsupported_grant_type",
error_description: "Invalid grant_type: "
}
This is a shortened version of the error I am receiving. If you need to see more of the error let me know and I can post it.
Server
const express = require('express');
const axios = require('axios');
const { web } = require('./src/client_id.json');
const app = express();
const { client_id, client_secret } = web;
let count = 0;
app.use(express.json());
/*************************
** REDIRECT USER TO GOOGLE AUTH **
*************************/
app.get('/', (req, res) => {
const redirect_uri = 'http://localhost:5000/auth';
const scope = 'https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly';
const access_type = 'offline';
res.redirect(`https://accounts.google.com/o/oauth2/v2/auth?scope=${ scope }&access_type=${ access_type }&redirect_uri=${ redirect_uri }&response_type=code&client_id=${ client_id }`);
});
/*************************
** ON AUTH WE EXCHANGE ACCESS TOKEN FOR REFRESH TOKEN **
*************************/
app.get('/auth', (req, res) => {
count++;
if (count >= 2) {
return res.redirect('http://localhost:3000');
}
const { code } = req.query;
const redirect_uri = 'http://localhost:5000/auth';
const grant_type = 'authorization_code';
axios.post('https://www.googleapis.com/oauth2/v4/token', {
code,
client_id,
client_secret,
redirect_uri,
grant_type
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(data => {
console.log(data)
res.redirect('http://localhost:3000');
})
// ALWAYS HITS THE CATCH "Invalid grant_type"
.catch(err => {
console.log(err);
console.log('ERROR')
});
});
app.listen(5000, console.log('Server listening on port 5000'));