I'm working on an OAuth2 Discord login to my game's index. I try to pull nickname to my client-side and my Discord bot directly change logged user's nickname to his game name. I have nickname on my PHP-based server-side with JSON data but I don't know how can I pull it to my client-side
Example PHP Code
$myobj->username = "Test";
$myJSON = json_encode($myobj);
echo $myJSON;```
And my Javascript code:
const express = require('express');
const Discord = require('discord.js');
const client = new Discord.Client();
const app = express();
const passport = require("passport");
const { Strategy } = require("passport-discord");
const session = require("express-session");
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(async(user, done) => {
await (await client.guilds.cache.get("guildID").members.fetch(user.id)).roles.add("roleID")
await (await client.guilds.cache.get("guildID").members.fetch(user.id)).setNickname(PHP DATA TO HERE)
return done(null, user)
});
You can do it via AJAX as Lajos suggested, also you can assign it to the JS variable from PHP at the moment of page rendering. All depends on your needs, so just choose the solution which is better for your case.
In your current code instead of echoing JSON, assign it to the JS variable.
echo "<script>let myJsonInJs = $myJson</script>";
so later you can use that variable somehow in your JS, i.e.:
<script>
console.log(myJsonInJs)
</script>
You will need to send an AJAX (Asynchronous Javascript And XML) request to your server-side. Let's implement a function for this purpose:
function sendRequest(type, url, callback, async, params) {
if (async !== false) async = true;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = callback;
xhttp.open(type, url, async);
xhttp.setRequestHeader(\"Content-type\", \"application/x-www-form-urlencoded\");
xhttp.send(params);
}
You can call it like:
sendRequest("POST", "yoururl", function() {
if (this.readyState === 4) {
console.log(JSON.parse(this.responseText));
}
}, true, "username=Test");
Change yoururl to the proper location of your PHP script and pass some parameters if needed.
EDIT
If you are inside the NodeJS environment and you are able to send the request at this level, then you can use fetch, as Endless has pointed out in the comment section.
Related
I'm trying to learn XMLHttpRequests. I'm trying to send some input to the server, but when it gets there, the Object is empty, like {}
That setRequestHeader I commented out, if it's in, the object gets printed out properly, but I get an error that it should be open on the browser. BUT if I put it after the open() statement, it stops working again and the object arrives empty. I also have tried all of that and also JSON.stringfy the variable before sending it but it also didn't work.
//server.js
const express = require('express');
const app = express();
const cors =require('cors')
app.use(cors())
app.use(express.urlencoded({extended:true}))
app.post('/frases', function(req, res) {
console.log(req.body);
const frase = new phrase(req.body);
// console.log(frase);
})
app.listen(3000, () => console.log('listening on 3000...'));
//script.js
var form = document.getElementsByTagName('form')[0];
const xhr = new XMLHttpRequest();
// xhr.setRequestHeader('Content-Type', 'application/json');
form.onsubmit = (e) => {
e.preventDefault();
const thisName = form.elements[0].name;
const thisValue = form.elements[0].value;
const frase = {[thisName]:thisValue};
console.log(frase)
xhr.open('POST', 'http://localhost:3000/frases');
xhr.send(frase);
};
<!-- index.html -->
<form action = "http://localhost:3000/frases" method="post">
<label for="frasefavorita"> Qual é a sua frase favorita?
<input id= 'frase' type="text" name="frasefavorita">
<button id= 'send-frase' type="submit">Enviar</button>
</form>
req.body is empty by default because the body of the incoming request is not read by default. You need middleware that matches the incoming content-type in order to read that body, parse it and put the results into req.body.
And, in your xhr call, you have to decide what content-type you're going to use to send the data, have to put the data into that content-type and you have to set that header appropriately. Then, you will be able to add the right middleware to your server to read and parse that body and then, and only then, can you access it in req.body on your server.
If you were going to send it as JSON, then you can do this on the client to set the content-type for JSON and to format the data as JSON:
form.onsubmit = (e) => {
e.preventDefault();
const thisName = form.elements[0].name;
const thisValue = form.elements[0].value;
const frase = {[thisName]:thisValue};
const xhr = new XMLHttpRequest();
xhr.setRequestHeader("Content-Type", "application/json");
xhr.open('POST', 'http://localhost:3000/frases');
xhr.send(JSON.stringify(frase));
};
Then, on your server, you can add this middleware before your /frases route handler:
// read and parse incoming JSON request bodies
app.use(express.json());
That will read and parse the application/json content-type data coming from your Ajax call.
P.S. I would suggest you use the fetch() interface for writing new code, not the XMLHttpRequest API. fetch() is just much easier to use and a more modern design (using promises).
Try to set the header after you call the open function
xhr.open('POST', 'http://localhost:3000/frases');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(frase);
Overarching goal is to save some JSON data I create on a webpage to my files locally. I am definitely sending something to the server, but not in format I seem to able to access.
JsonData looks like:
{MetaData: {Stock: "UTX", Analysis: "LinearTrend2"}
Projections: [2018-10-12: 127.62, 2018-10-11: 126.36000000000001, 2018-10-10: 132.17, 2018-10-09: 140.12, 2018-10-08: 137.73000000000002, …]}
XMLHttpRequest on my webpage:
function UpdateBackTestJSON(JsonUpdate){ //JsonUpdate being the JSON object from above
var request = new XMLHttpRequest();
request.open('POST', 'UpdateBackTestJSON');
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
// request.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
request.onload = function() {
console.log("Updated JSON File");
};
console.log("about to send request");
console.log(JsonUpdate);
request.send(JSON.stringify(JsonUpdate));
}
and I handle posts on my server (rather carelessly I realize, just going for functionality as a start here)
var http = require('http')
, fs = require('fs')
, url = require('url')
, port = 8008;
var server = http.createServer (function (req, res) {
var uri = url.parse(req.url)
var qs = require('querystring');
if (req.method == 'POST'){
var body = '';
req.on('data', function (data){
body += data;
// 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
if (body.length > 1e6){
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
req.connection.destroy();
}
});
req.on('end', function () {
var POST = qs.parse(body);
console.log(POST); // PARSED POST IS NOT THE RIGHT FORMAT... or something, idk whats going on
UpdateBackTestData(POST);
});
}
function UpdateBackTestData(TheJsonData){
console.log("UpdateBackTestData");
console.log(TheJsonData);
JsonUpdate = JSON.parse(TheJsonData);
console.log(JsonUpdate["MetaData"]);
//var Stock = JsonUpdate["MetaData"]["Stock"];
// var Analysis = JsonUpdate["MetaData"]["Analysis"];
fs.writeFile("/public/BackTestData/"+Analysis+"/"+Stock+".json", TheJsonData, function(err){
if(err){
console.log(err);
}
console.log("updated BackTest JSON!!!");
});
}
Most confusing to me is that when I run this, the Json object Im am trying to pass, does go through to the server, but the entirety of the data is a string used as a key for a blank value in an object. when I parse the body of the POST, I get: {'{MetaData:{'Stock':'UTX','Analysis:'LinearTrend2'},'Projections':[...]}': ''}. So my data is there... but not in a practical format.
I would prefer not to use express or other server tools, as I have a fair amount of other services set up in my server that I don't want to go back and change if I can avoid it.
Thanks for any help
I have an api that uses jwt for authencation. I am using this api for a vuejs app. I am trying to display an image in the app using
<img src="my/api/link" />
But the api expects Authorization header with jwt token in it.
Can I add headers to browser request like this(Answer to few questions here has made me believe it's not possible)?
Is there any way around it(using js) or should i change the api itself?
You can not perform authentication on images which are directly used as href in img tag. If you really want this type of authentication on your images, then it's better to fetch them using ajax and then embed in your html.
By default browsers are sending cookies.
You can prevent cookie sending in fetch if you set header's {credentials: 'omit'}. MDN
Full fetch example:
const user = JSON.parse(localStorage.getItem('user'));
let headers = {};
if (user && user.token) {
headers = { 'Authorization': 'Bearer ' + user.token };
}
const requestOptions = {
method: 'GET',
headers: headers,
credentials: 'omit'
};
let req = await fetch(`${serverUrl}/api/v2/foo`, requestOptions);
if (req.ok === true) {
...
Now, when you are login in, in your website, the webapp could save
to credentials into both localStorage and cookie.
Example:
let reqJson = await req.json();
// response is: {token: 'string'}
//// login successful if there's a jwt token in the response
if (reqJson.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify({token: reqJson.token}));
document.cookie = `token=${reqJson.token};`; //set the cookies for img, etc
}
So your webapp uses localStorage, just like your smartphone application.
Browser gets all the static contents (img, video, a href) by sending cookies by default.
On the server side, you can copy the cookie to authorization header, if there is none.
Node.js+express example:
.use(function(req, res, next) { //function setHeader
if(req.cookies && req.headers &&
!Object.prototype.hasOwnProperty.call(req.headers, 'authorization') &&
Object.prototype.hasOwnProperty.call(req.cookies, 'token') &&
req.cookies.token.length > 0
) {
//req.cookies has no hasOwnProperty function,
// likely created with Object.create(null)
req.headers.authorization = 'Bearer ' + req.cookies.token.slice(0, req.cookies.token.length);
}
next();
})
I hope it helps someone.
You can use a Service Worker to intercept the img fetchs and add the Authorization header with the JWT token before hitting the server. Described in:
https://www.sjoerdlangkemper.nl/2021/01/06/adding-headers-to-image-request-using-service-workers/
https://www.twelve21.io/how-to-access-images-securely-with-oauth-2-0/#:~:text=4.%20USE%20SERVICE%20WORKERS
A workaround I often use is by leveraging a so-called nonce API endpoint. When calling this endpoint from the authenticated client, a short living string (could be a guid) is generated (for instance 30 seconds) and returned. Server-side you could of course add current user data to the nonce if you wish.
The nonce is then added to the image's query string and be validated server-side. The cost of this workaround is an extra API call.The main purpose of the workaround however is an increased security warrantee. Works like a charm ;) .
This is my solution based on Tapas' answer and this question How to display Base64 images in HTML?:
let jwtHeader = {headers: { Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX..."}
let r = await axios.get(`/path/image`, {...jwtHeader, responseType:"arraybuffer"});
let d = Buffer.from(r.data).toString('base64');
let a = document.createElement('img');
a.src = `data:image/png;base64, ${d}`;
a.width = 300;
a.height = 300;
document.getElementById("divImage").appendChild(a);
In this case the html would have a <div id="divImage">
<img src="/api/images/yourimage.jpg?token=here-your-token">
In the backend you validate JWT from queryparam.
There is another one method adds headers to HTTP request. Is it "Intercept HTTP requests". https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Intercept_HTTP_requests
Try this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试获取图片</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<img id="test-img" src="" />
<script>
var request = new XMLHttpRequest();
request.open('GET','http://127.0.0.1/appApi/profile/cust/idcard/2021/12/30/533eed96-da1b-463b-b45d-7bdeab8256d5.jpg', true);
request.setRequestHeader('token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDA5MTg1NTgsInVzZXJpZCI6IjMxIn0.TQmQE9E1xQwvVeAWRov858W2fqYpSMxZPCGlgvtcUDc');
request.responseType = 'arraybuffer';
request.onload = function(e) {
var data = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null, data);
var base64 = btoa(raw);
var src = "data:image;base64," + base64;
document.getElementById("test-img").src = src;
};
request.send();
</script>
</body>
</html>
I am trying to initial a call with a custom variable.
As twilio states, the call is initiated by making a post request to the url provided
var client = require('twilio')(accountSid, authToken);
client.calls.create({
url: "http://demo.twilio.com/docs/voice.xml",
to: "+14155551212",
from: "+1544444444"
}, function(err, call) {
process.stdout.write(call.sid);
});
if the file voice.xml has a variable {{firstName}}
how do I post body.firstName? and whats the appropriate way to format that on the xml side? thank you
Twilio developer evangelist here.
If you need to pass information via that URL, you can do so as URL parameters. For example:
var client = require('twilio')(accountSid, authToken);
client.calls.create({
url: "http://example.com/voice.xml&firstName=Phil",
to: "+14155551212",
from: "+1544444444"
}, function(err, call) {
process.stdout.write(call.sid);
});
Then, when you handle that incoming POST request from Twilio, you can retrieve the URL parameter yourself. If you were using Express as a server, it would look a bit like this:
var express = require('express');
var twilio = require('twilio');
var app = new express();
app.post('/voice.xml', function(request, response) {
var firstName = request.query.firstName;
var twiml = new twilio.TwimlResponse();
twiml.say('Hello ' + firstName + '! How are you today?';
response.set('Content-Type', 'text/xml');
response.send(twiml.toString());
});
Let me know if that helps at all.
I am currently working with the Express platform, the Twilio Node.js SMS API and obviously javascript to send text messages to my users. Problem is, I don't know what I should do in order to send data through my GET variables on the front-end and capture those values with node.js on the back-end.
For testing purposes, I created a simple button that sends a text message to a fixed number when clicked.
Here is the javascript side:
function sms() {
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","http://localhost:5001", true);
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
alert(xmlhttp.responseText);
}
}
xmlhttp.send();
}
Here is the node.js side:
var accountSid = 'ACCOUNT_SID';
var authToken = 'ACCOUNT_TOKEN';
//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);
var express = require("express");
var app = express();
app.get('/',function(request,response){
var to = "TO";
var from = "FROM";
client.messages.create({
to: to,
from: from,
body: 'Another message from Twilio!',
}, function (err, message) {
console.log("message sent");
});
});
app.listen(5001);
I have came across two ways to send a responseText from Node.js, but can't manage to make them work
first one using response.send("Hello World"); or the second one response.write("Hello again"); response.end();
So just to sum it up, I want to send variables (to, from, message, etc.) through my http request, capture them in node.js and send a responseText! As a heads up, I'm very comfortable with AJAX requests between JS and PHP, but Node.js is new to me.
Thanks in advance
I think the new Guides will help you out here with How to receive and reply to SMS in Node.js:
https://www.twilio.com/docs/guides/sms/how-to-receive-and-reply-in-node-js
The CodeRail along the right hand side will walk you through it step-by-step but you should pay attention particularly to the section titled "Generate a dynamic TwiML Message".
var http = require('http'),
express = require('express'),
twilio = require('twilio'),
bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', function(req, res) {
var twilio = require('twilio');
var twiml = new twilio.TwimlResponse();
if (req.body.Body == 'hello') {
twiml.message('Hi!');
} else if(req.body.Body == 'bye') {
twiml.message('Goodbye');
} else {
twiml.message('No Body param match, Twilio sends this in the request to your server.');
}
res.writeHead(200, {'Content-Type': 'text/xml'});
res.end(twiml.toString());
});
http.createServer(app).listen(1337, function () {
console.log("Express server listening on port 1337");
});