I wrote a rest api to handle all requests for my chat app, such as logging in, signing up, or sending a message. This works fine for my serverside code;however, I want logging in or signing up to send a request to the rest api instead. On the api, the request is never received from the client. I tried testing it basically in a similar way on a separate directly
I'm working on a chat app I started around a month ago
Code for server that handles logins:
app.route('/login').post(async (req, res) => {
console.log('login request')
var users = await serverController.listDocuments({
database:'chatbase',
collectionName:'users',
query:`{'username':'${req.body.usrnm}'}`
})
if(!users[0]) return res.send('Incorrect Credentials')
var user = new User(users[0])
var isCorrect = await bcrypt.compare(req.body.psw, user.password)
if(!isCorrect) return res.send('Incorrect Credentials')
res.send({token: user.token, username:user.username, id:user.id})
})
Code for client side:
let xhr = new XMLHttpRequest()
xhr.open("POST", 'https://api.domain.com')
xhr.setRequestHeader('Content-Type', "application/json");
xhr.onreadystatechange = () => {
if (xhr.status == 200) {
alert('Reqest succeeded');
}
alert(xhr.status)
}
xhr.send(JSON.stringify({
usrnm:'Example Username',
psw:'Example Password'
}))
Code for server(Works):
socket.on('login', credentials => {
var opt = {
uri:'https://message-api.glitch.me/login',
method:'POST',
body:credentials,
headers: {
'User-Agent': 'Request-Promise'
},
json:true
}
rp(opt)
.then(res => {
if(res == 'Incorrect Credentials') return socket.emit('loginFailed')
socket.emit('loginSuccess', res)
})
})
The serverside code receives creds from user and then forwards them to api. The server then receives either a token that the user can send messages using or it sends an incorrect login(Works). The api code simply routes various request types, such as creating servers or logging in(Works from serverside requests). The client side creates a reqyest and then sends it(Is never recieved)
Related
I'm working on authentication using Next.js and Strapi.
The client sends a post request with credentials to the Next.js server. Then, the server sends a post request to the Strapi API, passing the credentials, to log the user in. The server gets a JWT token and sets it as an HTTPonly cookie.
My question is: How do I also receive the JWT on the client side to do some fetching? I'm not really sure how to do this.
Client sends post request with credentials to server:
// -- /pages/account/login.js
const handleLogin = (e) => {
e.preventDefault()
axios.post("/api/login", {
identifier: `${credentials.email}`,
password: `${credentials.password}`,
remember: stayLoggedIn,
})
.then(response => {
// I need to access the JWT here
Router.push("/")
response.status(200).end()
}).catch(error => {
console.log("Error reaching /api/login ->", error)
})
}
Server calls Strapi API and logs the user in, receiving a JWT token and setting it as a cookie:
// -- /pages/api/login.js
export default (req, res) => {
const {identifier, password, remember} = req.body;
// Authenticate with Strapi
axios.post(`${API_URL}/api/auth/local`, {
identifier, password
})
.then(response => {
const jwt = response.data.jwt; // I need to pass this back to client
console.log("Got token: ", jwt)
// Set HTTPonly cookie
if (remember === false) {
res.setHeader(
"Set-Cookie",
cookie.serialize("jwt", jwt, {
httpOnly: true,
secure: process.env.NODE_ENV !== "development",
maxAge: 60 * 60 * 24, // Logged in for 1 day
sameSite: "strict",
path: "/",
})
)
} else {
//...
}
console.log("Login successful")
res.status(200).end()
})
.catch(error => {
console.log("Error logging in", error)
res.status(400).end()
})
}
The JWT the server receives from the request must be send back to the client. How do I do this? I seem to be lost...
Thanks!
Figured it out. I can just use res.status(200).end(dataFromServer). I knew it was something simple.
I'm writing a login page for a quiz application. On pressing the login button, I'm sending a post request to the server, the server the redirects to the home page where the questions are listed. The problem is that it only refreshes the login page.
// FRONT-END code
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const xhr = new XMLHttpRequest();
// I only put this in to reload the page somehow
xhr.onreadystatechange = () => {
window.location.href = '/';
};
xhr.open('POST', '/login');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
username,
password,
}));
// SERVER-SIDE code
router.post('/login', jsonParser, (req, res) => {
if (req.body.username === undefined || req.body.password === undefined) {
console.log('Doesn\'t have neccesarry elements');
res.status(400).render('error', { message: 'Doesn\'t have necessary elements' });
} else {
...
res.redirect('/');
}
});
I would like to mention that the / is also a template rendered page, maybe that is the problem?
The problem is on your FRONTEND, if client request the server using xml request it is doesn't redirect the page. So you have to redirect from client window.location.href after the xml request.
1.If it is error on servee Sent {status: error} to client like that,
2. check the status in the client if it is error change the path in clinen.
I am using the express framework in node and I don't know what is best practice or if this is the wrong thing to do but I wanted to send a status code e.g. res.status(200).send("Success"); if the form input matches with the server and if it does not match then send something like res.status(403).send("Forbidden");
Then in the webpage I can update the paragraph element with the sent response. So the user knows if it has been successful or not.
Is this possible? If it is how do I do it? And is there a better way?
For sure it is possible!
Taken from the express api reference:
res.status(code)
Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode.
res.status(403).end()
res.status(400).send('Bad Request')
res.status(404).sendFile('/absolute/path/to/404.png')
Generally sending status codes is the way to go. If you are sending data without a status code, express will add the 200 status code automatically, so you don't have to add it manually.
On the client side, you have to check for a non 2xx status code in your response object of your request. Here is an example using the fetch api.
fetch('/your/api')
.then((response) => {
if (!response.ok) { // Check for a non 2xx status code
throw new Error('Network response was not ok');
}
// Do something with the response data
})
.catch((error) => {
// This is only reached when a network error is encountered or CORS is misconfigured on the server-side
console.error('There has been a problem with your fetch operation:', error);
});
Example: Credentials Use Case
If you want to write a web page which has a form to enter user credentials to gain access to further content, I would suggest doing it the following way:
Client side:
// Function is listening to the submit event of your login form
function submitLoginForm() {
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
const options = {
method: 'POST',
body: JSON.stringify({ username, password }),
headers: {
'Content-Type': 'application/json'
}
};
return fetch('/api/login', options)
.then((response) => {
// Check for a non 2xx status code
if (!response.ok) {
// Show a failed login hint
showMessageBox('Login was not granted by the server. Please check you user name or password and try again.', 'error');
}
// Your login was successfull, manually redirect to user's dashboard, or whatever content...
})
.catch((error) => {
// This is only reached when a network error is encountered or CORS is misconfigured on the server-side
console.error('There has been a problem with your fetch operation:', error);
});
}
Server side:
app.post('/api/login', (req, res, next) => {
let username = req.body.username;
let password = req.body.password;
checkCredentials(username, password, (err) => {
if (err) {
return res.status(400).send('Wrong user name or password.');
}
// Consider adding a token or a cookie to the response object, so that the user keeps logged in.
return res.send('Access granted.');
});
});
I am attempting to write an App that sends a message with private_replies, but it always returns the following error:
{
message: '(#10903) This user cant reply to this activity',
type: 'OAuthException',
code: 10903,
fbtrace_id: 'HUzYz7nKBPV'
}
I have read a number of solutions, but none seem to be working for me, so I'm not sure if I've missed something or if the something on the Facebook API side has changed.
The App I am creating (currently based on a number of tutorials) waits for a user to mention a specific word in a comment on my page and will then send a message to the user via private_replies.
When I debug my Apps Page Access Token, I get this info:
Access Token Info
App ID 18**********164 : MTestChatBot
Type Page
Page ID 25**********999 : MTestPage
App-Scoped User ID
Learn More
10**********048 : <MY NAME>
User last installed this app via API N/A
Issued 1520423580 (on Wednesday)
Expires Never
Valid True
Origin Web
Scopes manage_pages, pages_show_list, read_page_mailboxes, pages_messaging, pages_messaging_phone_number, pages_messaging_subscriptions, public_profile
One of the 'solutions' I have read states that I need to have to App reviewed by Facebook first to get the read_page_mailboxes subscription, but as shown above, I should already have that permission. It also seems odd to get an App reviewed before I can test it.
I have tried giving a friend developer access to the App and Admin rights to the page. When they post comments I get the same error.
I have tried Publishing the page and all comments still get the same result.
In case it's of any use, here is a rough version of the App code:
'use strict';
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const request = require('request');
const express = require('express');
const body_parser = require('body-parser');
const app = express().use(body_parser.json());
app.listen(process.env.PORT);
app.get('/webhook', (req, res) => {
// Parse params from the webhook verification request
let mode = req.query['hub.mode'];
let token = req.query['hub.verify_token'];
let challenge = req.query['hub.challenge'];
// Check if a token and mode were sent
if (mode && token) {
// Check the mode and token sent are correct
if (mode === 'subscribe' && token === FB_VERIFY_TOKEN) {
// Respond with 200 OK and challenge token from the request
console.log('WEBHOOK_VERIFIED');
res.status(200).send(challenge);
} else {
// Responds with '403 Forbidden' if verify tokens do not match
res.sendStatus(403);
}
}
});
app.post('/webhook', (req, res) => {
// Parse the request body from the POST
let data = req.body;
if (data.object === 'page') {
data.entry.forEach(function(pageEntry) {
var pageID = pageEntry.id;
var timeOfEvent = pageEntry.time;
if (pageEntry.hasOwnProperty('changes')) {
pageEntry.changes.forEach(function(changes){
if(changes.field === 'feed' && changes.value.item === 'comment' && changes.value.verb === 'add'){
var messageData = {
message: 'Hello'
};
privateReply(messageData, changes.value.comment_id);
}
});
}
});
}
})
function privateReply(messageData, comment_id) {
request({
uri: 'https://graph.facebook.com/v2.12/' + comment_id + '/private_replies',
qs: { access_token: FB_PAGE_ACCESS_TOKEN },
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
} else {
console.error('Private Replies Failed: ', response.statusCode, response.statusMessage, body.error);
}
});
}
All advice gratefully received.
It is maybe a facebook glitch or something. But the user is somehow blocked from receiving private reply from your page
I have strange issue. Basically the client will send a request i.e:delete chat, but Server will reject, since client is not authorized.
however, the client keep repeating the same request, even if I open new browser and load the same address. Both browser will keep requesting the previous action. my code looks something like this:
Client
socket.on(username, (res) => {
show(res.err)
})
socket.send({
type: "delete_chat",
username: username,
id: chat_id
})
Server:
io.sockets.on("connection", (socket) => {
socket.on("message", (data) => {
if(data.type === "delete_chat"){
Chat.delete(chatid, (err, res) => {
io.emit(username, {err:res}) //send error to username
});
}
})
})