Discord oauth API inavlid_reuqest error. - express.js - javascript

I have created multiple website using this tutorial https://medium.com/#orels1/using-discord-oauth2-a-simple-guide-and-an-example-nodejs-app-71a9e032770 and they all worked perfectly until yesterday. The problem is that when a user authenticates and goes to https://mywebsite.com/api/discord/callback?code={discord response code} the api gets an error when trying to convert the code with a access_token.
This is the code for my discord api callback:
const router = express.Router();
const fetch = require('node-fetch');
const FormData = require('form-data');
const btoa = require('btoa');
const { catchAsync } = require(__dirname+'/utils');
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const redirect = encodeURIComponent('https://mywebsite.com/api/discord/callback');
router.get('/login', (req, res) => {
res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`);
});
router.get('/callback', catchAsync(async (req, res) => {
if (!req.query.code) throw new Error('NoCodeProvided');
const code = req.query.code;
const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const response = await fetch(`https://discord.com/api/oauth2/token?grant_type=authorization_code&code=${code}&redirect_uri=${redirect}`,
{
method: 'POST',
headers: {
Authorization: `Basic ${creds}`,
},
});
const json = await response.json();
console.log(json)
res.redirect(`/finallogin/?token=${json.access_token}`);
}));
module.exports = router;
When a user authenticates, he gets redirected to https://mywebsite.com/finallogin/?token=undefined and I'm getting this error on console:
error: 'invalid_request',
error_description: 'Missing "code" in request.'
}
This was working perfectly before and just randomly broke a few days ago on all of my websites. Any help / solution / idea will be appreciated.
(Note: the "https://mywebsite.com" is just an example and not my actual website url)
Thanks,
RealPower2Maps.

Related

Etsy API authetication - Cannot GET error

I'm very rusty in javascript and haven't touched it in a decade so I was following an Etsy tutorial on how to request an API access token.
I'm running a node.js node on my localhost and ngrok to get a proper URL for it (seems like localhost doesn't work for etsy). The authentication seems to work (I can log in in etsy with it), until the part in the tutorial where I need to send the API information onto the next page (to actually start pulling the etsy store data).
As soon as the etsy authentication page get redirected to the next page I alway get the error "Cannot GET views/index.hbs"
The page is in the views folder in the project folder.
I'm really not sure what the problem is, maybe the way the files are structured in the folder?
Thanks a lot for the help.
This is how the code looks like:
// Import the express library
const express = require('express')
const fetch = require("node-fetch");
const hbs = require("hbs");
// Create a new express application
const app = express();
app.set("view engine", "hbs");
app.set("views", `${process.cwd()}/views`);
// Send a JSON response to a default get request
app.get('/ping', async (req, res) => {
const requestOptions = {
'method': 'GET',
'headers': {
'x-api-key': 'xxxxxxxxxxxxxxx',
},
};
const response = await fetch(
'https://api.etsy.com/v3/application/openapi-ping',
requestOptions
);
if (response.ok) {
const data = await response.json();
res.send(data);
} else {
res.send("oops");
}
});
// This renders our `index.hbs` file.
app.get('/', async (req, res) => {
res.render("index");
});
/**
These variables contain your API Key, the state sent
in the initial authorization request, and the client verifier compliment
to the code_challenge sent with the initial authorization request
*/
const clientID = 'xxxxxxxxxxxxxxxx';
const clientVerifier = 'xxxxxxxxxxxxxxxxxxxxxx';
const redirectUri = 'https://xxxxxxx/views/index.hbs';
app.get("/oauth/redirect", async (req, res) => {
// The req.query object has the query params that Etsy authentication sends
// to this route. The authorization code is in the `code` param
const authCode = req.query.code;
const tokenUrl = 'https://api.etsy.com/v3/public/oauth/token';
const requestOptions = {
method: 'POST',
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: clientID,
redirect_uri: redirectUri,
code: authCode,
code_verifier: clientVerifier,
}),
headers: {
'Content-Type': 'application/json'
}
};
const response = await fetch(tokenUrl, requestOptions);
// Extract the access token from the response access_token data field
if (response.ok) {
const tokenData = await response.json();
res.send(tokenData);
} else {
res.send("oops");
}
});
app.get("/welcome", async (req, res) => {
// We passed the access token in via the querystring
const { access_token } = req.query;
// An Etsy access token includes your shop/user ID
// as a token prefix, so we can extract that too
const user_id = access_token.split('.')[0];
const requestOptions = {
headers: {
'x-api-key': clientID,
// Scoped endpoints require a bearer token
Authorization: `Bearer ${access_token}`,
}
};
const response = await fetch(
`https://api.etsy.com/v3/application/users/${user_id}`,
requestOptions
);
if (response.ok) {
const userData = await response.json();
// Load the template with the first name as a template variable.
res.render("welcome", {
first_name: userData.first_name
});
} else {
res.send("oops");
}
});
// Start the server on port 3003
const port = 3003;
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});

Integrate Nodejs Backend with React Frontend App

I am building an app that uses node.js for backend and react for frontend. In the backend, i have 2 functions that implement a post request.
In my react function:
I want to show a spinner while waiting for the response data from the API request.
For the triggerGrading function which only returns ok if successful, I want to be able to return a custom message in the frontend.
Here are my functions, and they work fine on postman. However, I am experimenting with NodeJS and React and want to know if there's any further logic I need to add to these backend functions to be able to accurately implement the spinner and a custom message return in the UI?
grading.js
const BASE_URL = htttp://localhost:8080
const postSubject = async (req, res, next) => {
const headers = {
"Score-API-Version": "v2",
"Content-type": "application/json",
};
const body = { name: 'Adam Lawrence' };
try {
const resp = await axios.post(`${BASE_URL}/subject`, body, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
const triggerGrading = async (req, res, next) => {
const { id } = req.params;
const headers = {
"Content-type": "application/json",
"Score-API-Version": "v2",
};
try {
const resp = await axios.post(`${BASE_URL}/start/${id}`, { headers });
const response = resp.data;
res.send(response);
} catch (err) {
if (err.response) {
res.status(err.response.status).send(err.response.data);
} else if (err.request) {
res.send(err.request);
}
next(err);
}
};
server.js
const express = require("express");
const flows = require("./grading.js");
const cors = require("cors");
const app = express();
app.use(cors());
const PORT = 5050;
app.use(express.json());
app.listen(PORT, () => {
console.log(`Running this application on the PORT ${PORT}`);
});
app.post("/subject", grading.postSubject);
React query is very easy comfy, but if you just want to explore a little bit on your own you can play with this example in codepen.
In order to show a spinner while the request is being made you can use useState:
const handleClickSpin = async()=>{
setIsLoading(true)
await postSubject()
setIsLoading(false)
}
and then conditionally show the spinner.
For the second part of your question, I assumed you didn't want to send the custom message from your sever, so I just added another flag with conditional rendering.

POST data passed from frontend JS to Nodejs/Expressjs is always undefined

I have a frontend JS script that takes text input from an HTML text box and sends it to an expressjs server. The body of the POST request, though, is always undefined, or depending on how I tweak things, returning as "{ }" if I view it via console.log( ). As I'm new to this, I can't seem to see what's going wrong.
Front end js:
async function submitCity(){
let x = document.getElementById("wg_input").value;
console.log("Successfully captured city name:", x);
let toWeather = JSON.stringify(x);
console.log("Input data successfully converted to JSON string:", toWeather);
const options = {
method: 'POST',
mode: 'cors',
headers: {'Content-Type': 'text/plain'},
body: toWeather
}
fetch('http://localhost:3000', options)
.then(res => console.log(res))
.catch(error => console.log(error))
}
Backend:
// Dependencies
const express = require('express');
const bp = require("body-parser");
const request = require("request");
const jimp = require('jimp');
const cors = require('cors');
const wgServer = express();
const port = 3000;
// Dotenv package
require("dotenv").config();
// OpenWeatherMap API_KEY
const apiKey = `${process.env.API_KEY}`;
// Basic server initialization
wgServer.use(cors())
wgServer.use(bp.json())
wgServer.use(bp.urlencoded({ extended: true }))
wgServer.listen(port, function() {
console.log(`Example app listening on port ${port}!`)
});
wgServer.post('/', async function (req, res) {
res.set('Content-Type', 'text/plain');
console.log(req.body)
res.send('Hello World');
//const data = await req.body;
// let jsonData = JSON.stringify(req.body);
// res.status(201);
//res.json();
});
The returned data is supposed to be a string of about 15 characters, give or take a few (a city and state). I thank you in advance.

getting a 405 error - POST is not allowed?

I have this fetch request to get some auth data from my form to the server
const registerUser = async (e) => {
e.preventDefault()
const userName = document.getElementById('username').value
const password = document.getElementById('password').value
const confirm = document.getElementById('password-confirm').value
//Make this better with DOM and css later
if (password !== confirm){
alert('Passworfds dont match')
}
const result = await fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username,
password
})
}).then((res) => res.json())
}
The server code to accept this is so far nothing other than this
app.post('/api/register', async (req, res) => {
console.log(req.body)
res.json({ status: 'ok' })
})
When i hit the submit button i am getting a POST - 405 - method not allowed error in the console if anyone can please help?
Do you have installed the Body-Parser?
var bodyParser = require("body-parser");
var jsonParser = bodyParser.json();
app.post("/api/register", jsonParser, (req, res) => {
console.log(req.body);
res.json({ status: "ok" });
});
This was slightly foolish and a really simple mistake.
My severs serves my html and the login form was running on live server through VScode on the wrong port. A Simple routing issue I have now solved!

Can't redirect to '/api/auth/slack/callback' after Slack authentication

I'm implementing Slack webhook authentication with Firebase Cloud Function. However, the app is redirected to /api/auth/slack/undefined after choosing the channel I get notified. It should be redirected to /api/auth/slack/callback.
 Error: could not handle the request (/api/auth/slack/undefined)
Slack app setup done:
The Frontend code:
const slackAuthorizeURL= (uid) =>
`https://slack.com/oauth/v2/authorize?client_id=${process.env.REACT_APP_SLACK_CLIENT_ID}&scope='incoming-webhook'&redirect_uri=${process.env.REACT_APP_CLOUD_FUNCTIONS_ORIGIN}/api/auth/slack/callback&uid=${uid}&redirectTo=${window.location.href}`
<a href={slackAuthorizeURL('uid')}>Add to Slack</a>
The Server code:
const { WebClient } = require('#slack/web-api')
app.get('/auth/slack/callback', (req, res) => {
handleSlackUserInfo(req)
res.redirect(req.session.redirectTo)
})
const handleSlackUserInfo = async (req) => {
const { code, uid, redirectTo } = req.session
const result = await new WebClient().oauth.v2.access({
client_id: config.slack.client_id,
client_secret: config.slack.client_secret,
code,
})
console.log("result", result)
}
I added uid=${uid}&redirectTo=${window.location.href} after callback url. Is this wrong too?

Categories