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}`);
});
Related
I'm trying to get new access token from spotify by sending the refresh token to spotify token endpoints but it's returning this {error: 'invalid_grant', error_description: 'Invalid refresh token'}
this is my code:
const basic = Buffer.from(
`${import.meta.env.VITE_CLIENT_ID}:${import.meta.env.VITE_CLIENT_SECRET}`
).toString("base64");
const params = new URLSearchParams();
params.append("grant_type", "refresh_token");
params.append("refresh_token", import.meta.env.VITE_REFRESH_TOKEN);
const response = await fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded"
},
body: params.toString()
});
const result = await response.json();
return result;
It's suppose to return a new access token but it's returning error for some reasons i don't understand.
Note: I got the access token and refresh token from this website https://alecchen.dev/spotify-refresh-token/ after inputting my client id and client secret. If i use the access token directly to make a request to spotify api it works but i need to refresh it to get a new one but it's returning error
You needs to call this format in body of POST.
grant_type = refresh_token
refresh_token = <received refresh_token>
access_token= <received access_token>
The website https://alecchen.dev/spotify-refresh-token/ has a potential leak your credential.
I will shows getting refresh token in local and update refresh token.
Demo Code.
Save as get-token.js file.
const express = require("express")
const axios = require('axios')
const cors = require("cors");
const app = express()
app.use(cors())
CLIENT_ID = "<your client id>"
CLIENT_SECRET = "<your client secret>"
REDIRECT_URI = '<your redirect URI>' // my case is 'http://localhost:3000/callback'
SCOPE = [
"user-read-email",
"playlist-read-collaborative"
]
app.get("/login", (request, response) => {
const redirect_url = `https://accounts.spotify.com/authorize?response_type=code&client_id=${CLIENT_ID}&scope=${SCOPE}&state=123456&redirect_uri=${REDIRECT_URI}&prompt=consent`
response.redirect(redirect_url);
})
app.get("/callback", async (request, response) => {
const code = request.query["code"]
await axios.post(
url = 'https://accounts.spotify.com/api/token',
data = new URLSearchParams({
'grant_type': 'authorization_code',
'redirect_uri': REDIRECT_URI,
'code': code
}),
config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
params: {
'grant_type': 'client_credentials'
},
auth: {
username: CLIENT_ID,
password: CLIENT_SECRET
}
})
.then(resp1 => {
axios.post(
url = 'https://accounts.spotify.com/api/token',
data = new URLSearchParams({
'grant_type': 'refresh_token',
'refresh_token': resp1.data.refresh_token,
'access_token': resp1.data.access_token
}),
config = {
auth: {
username: CLIENT_ID,
password: CLIENT_SECRET
}
}
).then(resp2 => {
return response.send(JSON.stringify([resp1.data, resp2.data]));
})
});
})
// your port of REDIRECT_URI
app.listen(3000, () => {
console.log("Listening on :3000")
Install dependencies
npm install express axios cors
Run a local server and access it
node get-token.js
Open your browser and enter this address
http://localhost:3000/login
It will get code and both tokens then exchange the exchanged token.
It Will display both tokens and exchanged token in Browser.
Result
First red box is get access-token and refresh-token
Second red box is to grant the refresh-token
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.
I know the basics of coding but I'm trying to understand API's, at the moment I'm trying to make an API that authorizes a user so I can see their information in a game.
Essentially I need to send data to my client from my server which is running Node.js and Express. I have managed to get the user authenticated but I then need to save that information as a cookie for later use.
The webapp starts on index.html and the API redirects the user back to auth.html.
Server Side Code
require('dotenv').config();
const express = require('express');
const {
addAsync
} = require('#awaitjs/express');
const app = addAsync(express());
const path = require('path');
const url = require('url');
const fetch = require("node-fetch");
const base64 = require('base-64');
const http = require('http');
// config libraries
const client_secret = process.env.CLIENT_SECRET;
// get env variables
function getCode(req) {
var ru = url.format({
protocol: req.protocol,
host: req.get('host'),
pathname: req.originalUrl
});
return ru.split("code=")[1];
}; // parse url to get auth code
const port = process.env.PORT || 4645;
app.listen(port, () => {
console.log(`listening on port ${port}`);
}); // set http server
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
}); // set '/' as index.html
app.getAsync('/auth', async (req, res) => {
res.sendFile(path.join(__dirname, 'auth.html'));
const code = getCode(req);
const options = {
method: 'POST',
headers: {
'Authorization': `Basic ${base64.encode(`35544:${client_secret}`)}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `grant_type=authorization_code&code=${code}`
}
const obj = await fetch('https://www.bungie.net/platform/app/oauth/token/', options); // response
const data = await obj.json(); // json response = data
console.log(data);
// send json to client
res.json(data);
res.end();
});
app.get('/logout', async (req, res) => {
res.redirect('/');
});
Client Side Code (index.html)
<head>
<script>
// code
</script>
</head>
<body>
index.html <br>
<a href='https://www.bungie.net/en/OAuth/Authorize?client_id=35544&response_type=code'>log in</a> <br>
</body>
Client Side Code (auth.html)
<head>
<script>
// catch json from server
const options = {
url: '/auth',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
fetch(options).then(response => {
console.log(response);
})
</script>
</head>
<body>
auth.html <br>
<a href='/logout'>log out</a>
</body>
I know it's a lot but I hope someone can help me on this...
Thanks.
Edit:
I forgot to say that currently the client does not recieve the information at any point, and if it did i am unsure how to catch the response at the right time...
Thanks to everyone who already responded.
Without bothering to puzzle-out your code ... "never trust the client."
Never try to send the client any meaningful data as the content of a cookie. The cookie's value should always be a perfectly-meaningless value – a "nonce" – which you can then refer to in order to look up anything you need to know from your server-side database. "You can never trust the client-side."
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.
In order to avoid cross origin issues, I've got a front end javascript that's querying a backend node.js server, which grabs data from an api on a different origin:
const API_URL = [SOME_OTHER_SERVER];
const API_TIMEOUT = 1000;
const API_TOKEN = [SOME_TOKEN]
const app = express();
const PORT = 3001;
app.use(cors());
app.get('/getBackendData', async(req, res)=> {
try {
const response = await axios.get(API_URL,{
timeout: API_TIMEOUT,
headers: {
'Authorization': `Token ${API_TOKEN}`,
'Access-Control-Allow-Origin': '*'
}
});
console.log(response.data.data); //this works to retrieve and log the data
return response.data.data; //I want this to return the data to the front end
} catch (error) {
console.error(error);
return error;
}
});
app.listen(PORT, function() {
console.log('backend listening on port %s.', PORT);
});
On the front end, I'm querying my node.js backend:
const BACKEND_API_URL = 'http://localhost:3001/getBackendData';
async function getData()
{
let response = await fetch(BACKEND_API_URL, {
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
}
});
let data = await response;
return data;
}
getData()
.then(data => console.log(data)); //does not log the data from the backend
What am I doing wrong that I can't get a response from my node.js backend on the frontend?
You don't can use return in express route.
use instead res object like this: res.send(response.data.data)
see: https://expressjs.com/pt-br/api.html#res