Make http request within node js routes - javascript

I am building a slideshow that pulls pictures with a certain tag on instagram. The Instagram API requires me to make a call to their auth URL to receive an access token. Using node js and express I built out the backend like so:
var express = require('express');
var app = express();
app.use(express.static('public'));
app.listen(4000,function(){
console.log("Listening to app on localhost 4000");
})
app.get('/',function(req,res){
1. make call to Instagram authorization URL:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:4000&response_type=code
2. URL will be redirected with access code parameter
3. Use access code to make POST request to receive access token to be able to make GET requests.
})
My question is how do I make a request to visit that url within NodeJS/Express? Is it just a normal http.request()?
I don't want to user to go through the redirect process so that's why I want to put it in Node. I'm following these instructions https://www.instagram.com/developer/authentication/

You can do a redirect or use a npm library like instagram-node-lib
var express = require('express');
var request = require('request');
var app = express();
app.use(express.static('public'));
app.listen(4000, function () {
console.log("Listening to app on localhost 4000");
})
app.get('/', function (req, res) {
res.redirect('https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://localhost:4000/mycallback&response_type=code')
})
app.get('/mycallback', function (req, res) {
//handle token retrieval here
//do a get request as per the instagram documentation using the code sent back
var code = req.query.code
var url = 'https://api.instagram.com/oauth/access_token'
var options = {
method: 'post',
body: {
client_secret: 'CLIENT_SECRET',
grant_type: 'authorization_code',
redirect_uri: 'AUTHORIZATION_REDIRECT_URI',
code: code
},
json: true,
url: url
}
request(options, function (err, res, body) {
//body should look something like this
// {
// "access_token": "fb2e77d.47a0479900504cb3ab4a1f626d174d2d",
// "user": {
// "id": "1574083",
// "username": "snoopdogg",
// "full_name": "Snoop Dogg",
// "profile_picture": "..."
// }
// }
})
})
You will always require the redirect as that is how oAuth works. The user enters a password on the Instagram site. A code is sent back to your server via a callback url (redirect). You then use that code to retrieve the user token. You can then use the authorization token for subsequent calls.

Related

Is it possible to implement socket.io connection in express route?

I implement a payment service which depend on one of my express route as a callback route, so whenever a user want to make a payment, they will be redirected to this payment service link which entirely different my backend/frontend domain. After a successful payment, user will then be redirected to my express GET route (callback route), in this route is where I give users their asset and then redirect them to the frontend.
EXPECTATION
My expectation is, whenever a user make a purchase, I want a real time update on the frontend for others to see some details about the purchase without refreshing their browser.
WHAT I'VE TRIED
I had think socket.io would solve this, like adding a socket connection in the route to then push the data to the frontend. But after making lot of research, no solution seems to work for me.
HERE IS A SIMPLE CODE OF WHAT I'VE TRIED
=============================== server.js ========================
const express = require("express")
const app = express()
const http = require("http")
const cors = require("cors")
const session = require("express-session")
const runSocket = require("./runSocket")
const { Server } = require("socket.io")
app.use(cors())
app.use(express.json())
const server = http.createServer(app)
server.listen(3004, () => {
console.log("SERVER IS RUNNING")
})
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
})
const postRoute = require("./routes/postData")(io)
app.use("/post-data", postRoute)
==================================== postData Route ======================================
module.exports = function (io) {
router.post("/", async (req, res) => {
const data = req?.body?.data.message
const room = req?.body?.data?.room
io.on("connection", (socket) => {
console.log("Socket Running...")
socket.to(room).emit("the_message", data)
})
console.log("Under socket...")
return res.status(200).json({ data: req.body.data })
})
return router
}
This log: in postData route is not printing console.log("Socket Running...")
EXPECTATION
My expectation is, whenever a user make a purchase, I would like to make a real time update on the frontend for others to see some details about the purchase.
UPDATE: The Payment Gateway config looks somthing like this:
const { body } = await got.post("https://payment-provider-link", {
headers: { Authorization: "Bearer token for payment" },
json: {
email: "email#gmail.com",
amount: amount * 100,
initiate_type: "inline",
callback_url: `${BackendBaseUrl}/payment-callback`, // <<<============
},
})
Okay so you don't need the io.on("connection") in ur route. Remove that piece of code and simply change it to io.to(room).emit("the_message", data). Also make sure to have the other sockets joined the room ur trying to emit to otherwise they won't receive the data.

Getting a variable from a Server script to a Client script

Here's the current issue i'm struggling with. I'm on a webapp project, in which I have 2 scripts :
A script called start.js in which I initialize the server and initialize a variable, token. This script is ran when I start the webapp.
A script called viewer.js which initialize a viewer. That viewer requires the previous token to work.
I can't generate the token from the client side, because it requires NodeJS, and as far as I understood NodeJS doesn't work on Client side.
I've tried to use global variables, global methods, or HTTP requests, but none of these methods seems to work so far. Any tip on how to do it ?
Here is what I tried:
// start.js
const ForgeSDK = require('forge-apis');
const express = require('express');
const path = require('path');
var app = express();
app.use('/static', express.static(__dirname + '/static'));
/**
* Token generation
*/
oAuth2TwoLegged.authenticate().then(function(credentials){
setToken(credentials.access_token)
}, function(err){
console.error(err);
});
function setToken(newToken) {
console.log("Definition du nouveau token")
token = newToken;
console.log(token)
};
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(3000, function () {
console.log('Token provider listening on port 3000')
});
// viewer.js
var token = '';
/**
* Viewer initialization
*/
You can pass a callback to your config options to obtain the token (usually via ajax) to requests:
var options = {
env: 'AutodeskProduction',
getAccessToken: function(onGetAccessToken) {
//
// TODO: Replace static access token string below with call to fetch new token from your backend
// Both values are provided by Forge's Authentication (OAuth) API.
//
// Example Forge's Authentication (OAuth) API return value:
// {
// "access_token": "<YOUR_APPLICATION_TOKEN>",
// "token_type": "Bearer",
// "expires_in": 86400
// }
//
var accessToken = '<YOUR_APPLICATION_TOKEN>';
var expireTimeSeconds = 86400;
onGetAccessToken(accessToken, expireTimeSeconds);
}
}
Autodesk.Viewing.Initializer(options, function onInitialized(){
...
See here for details.
And see here and here to create an endpoint to generate access tokens in your Node backend.

How to authenticate LinkedIn using Node.js and simple-oauth2

I am writing a node.js app to authenticate with LinkedIn and it isn't working. The problem is that I am redirecting to (what appears to be) the correct URL, but instead of being forwarded to a page that queries the user to authorize their credentials, I get a "page not found" message.
I have created a LinkedIn "App". Below are my "authorized redirect URLs":
HTML
<div id="root">
<button id="auth-button"> Login </button>
</div>
Client JS
function onSignInButtonClick() {
// Open the Auth flow in a popup.
window.open('/redirect', 'firebaseAuth', 'height=315,width=400');
};
var button = document.getElementById("auth-button");
button.addEventListener("click",function(){
onSignInButtonClick();
});
Server code
const credentials = {
client: {
id: "LINKEDIN_CLIENT_ID-1-2-3-4",
secret: "LINKEDIN_CLIENT_SECRET-1-2-3-4",
},
auth: {
tokenHost: 'https://www.linkedin.com/oauth/v2/authorization'
}
};
const oauth2 = require('simple-oauth2').create(credentials);
var express = require("express");
var app = express();
app.use(express.static("public"));
app.get('/', (req, res) => {
res.sendFile('landing.html',{
root:'public'
})
});
app.get('/redirect', (req, res) => {
const redirectUri = oauth2.authorizationCode.authorizeURL({
response_type:"code",
redirect_uri: "http://www.localhost:3000/callback",
state: "some-cryptic-stuff-98471871987981247"
});
res.redirect(redirectUri);
});
app.get('/callback',(req, res) => {
console.log("linkedin-callback route invoked");
res.send("linked in callback working")
});
app.listen(3000, function(err) {
console.log('Server works');
});
When the user clicks the button they are redirected to a URL that is identical in structure to the one that is given as a "sample call" (below) in the LinkedIn developer reference.
https://developer.linkedin.com/docs/oauth2#
However instead of seeing the prompt in the image above, my code gives them this:
The redirect_uri you have registered in LinkedIn (http://localhost:3000/callback) is different to what you are actually sending (http://www.localhost:3000/callback). This might be the issue as it causes an invalid redirect_uri error.

How to use JWT in Client with AJAX

My application is a Node.js API with a client inside the same application.
I'm trying to implement a simple auth login that uses a JWT token generated by a Node.js API.
My logic is as follows:
Client: User submits login information to /auth/login route.
$.ajax({
url: "/auth/login",
type: "POST",
data: formData,
dataType: "json",
success: function(data, textStatus, jqXHR) {
if (typeof data.redirect == "string") {
window.location = data.redirect;
}
},
error: function(data) {
if (typeof fail === "function") fail(data);
}
});
API: Verify user and on success generates JWT and sends back to the client.
router.post("/login", async (req, res) => {
var login = { UID: req.body.UID, password: req.body.password };
AU.manualLogin(login)
.then(result => {
res.header("x-auth-token", result.token).json({
status: 200,
message: "success",
data: result.data,
redirect: "/dashboard"
});
})
.catch(err => next({ status: 400, message: err.message }));
});
Client: Saves JWT to the header and checks for redirect - In this case, I use window.location to direct to /dashboard after successful login. (this part I'm not sure about)
API: Middleware checks valid JWT on protected routes.
module.exports = function auth(req, res, next) {
const token = req.headers["x-auth-token"];
if (!token)
return res.status(401).send("Access denied. No token provided.");
try {
const decoded = jwt.verify(token, "jwtPrivateKey");
req.user = decoded;
next(); //pass control to next middleware
} catch (ex) {
res.status(400).send("Invalid token.");
}
};
The Problem:
The token is definitely being sent from API -> Client. But I have no idea how to handle the token from the client-side. I think the issue might be to do with the window.location redirect as at this point it does not seem to be sending the x-auth-token to the API.
What I have tried
I have tested the solution with Postman from end-to-end and it works fine. That probably proves that it isn't the API side that has the issue.
I've also tried these sources:
Pass request headers in a jQuery AJAX GET call
Adding custom header in HTTP before redirect
How to add header to request in Jquery Ajax?
jwt on node - how does the client pass the token back to the server
You need kind of a storage to keep the token. Otherwise the user has always to login again after he closes the browser/tab. So it's quite common to keep the token in local or session storage.
Approach 1: Use a single page application (SPA) framework like angular, vue.js, react etc. to protect your routes client-side
Approach 2: You can request only html and css (view) from your backend and then store the token after a login procedure. With a valid token, fetch the (protected) data with ajax requests. Redirect to the login page if a ajax request returns the status code 401 (unauthorized) or a user wants to access the protected route without having a token stored. This is perhaps the most suitable for you.
Approach 3: Use Node.js with a backend framework like express and store auth information in a server side session
index.js
const express = require('express');
const session = require('express-session');
const app = express();
app.use(require("cookie-parser")());
app.use(session({ secret: 'aslwezoweasdfasdlkfalksdfhweelaerfcv', resave: false, saveUninitialized: true}));
routes/protectedRoutes.js
const express = require('express');
const router = express.Router();
router.all("/*", util.handleAuthenticate); // check auth on every request
// other routes
indexController.js (login functionality)
module.exports.login = function(req, res) {
if(!req.session.name) {
// check username/password --> db lookup
// if valid:
req.session.name = ...
// redirect to home or backref
// else: redirect to login
}
}
util/security.js
function isLoggedIn(req) {
return !!req.session.name;
}
function handleAuthenticate(req, res, next) {
if(isLoggedIn(req))
{
next();
}
else
{
// redirect to login page
}
}

Cannot GET / DELETE Express.js

I have this script with which I'm trying to POST, GET and DELETE some stuff.
When I try POST or GET, the right messages are logged, but when I try DELETE, I get the following error:
Cannot GET /del_user
The URL I'm using is http://127.0.0.1:8081/del_user
What can be wrong in here?
var express = require('express');
var app = express();
// This responds with "Hello World" on the homepage
app.get('/', function (req, res) {
console.log("Got a GET request for the homepage");
res.send('Hello GET');
})
// This responds a POST request for the homepage
app.post('/', function (req, res) {
console.log("Got a POST request for the homepage");
res.send('Hello POST');
})
// This responds a DELETE request for the /del_user page.
app.delete('/del_user', function (req, res) {
console.log("Got a DELETE request for /del_user");
res.send('Hello DELETE');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
console.log("Got a GET request for /list_user");
res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
console.log("Got a GET request for /ab*cd");
res.send('Page Pattern Match');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I solved it by changing the app.delete to app.get and then placing the required remove statement inside the app.get. Something like this :-
app.get('/delete/:userId', (req, res) => {
Users.remove({ _id: req.params.userId }, (error, posts) => {
if (error) {
console.warn(error);
}
else {
data = posts
res.render("delete", {"data": data})
}
});
});
In your code you're binding the /del_user URL to the HTTP DELETE method.
So all you need to do is specify the DELETE method in your application or in Postman.
If you're not using it, it's an App in Google Chrome and you might want to download it, it makes your life a LOT easier ;)
Also, since the HTTP method is already declared to be DELETE, there is no need to specify it in the URL.
This is part of the RESTful working.
If you are using AJAX to try your code, you need to specify the method, which is delete.
$.ajax({
url: "http://127.0.0.1:8081/del_user",
type: "DELETE"
});

Categories