Azure Mobile Apps - Table Middleware - node.js

I'm working with a node app for Azure Mobile Apps.
I have an Easy Table with a read operation that looks something like this:
table.read(function (context) {
context.query.where({ _user_id: context.req.userId });
return context.execute();
});
Now I want to add some middleware before that function runs which adds userId into the req, and so I thought I was supposed to do something like this:
table.use((req,res,next) => {
req.userId = "1234";
next();
}, table.operation);
Now, inside the table.read, if i console.log(context.req.userId) it comes out correct, but for some reason after adding thing .use, context.query becomes undefined. When I take off table.use, context.query.where({ _user_id: "1234" }) works perfectly.
How am I supposed to do this middleware properly within Azure Mobile Apps? Why is defining table.use messing with context.query?

Try adding the middleware at the application level instead:
mobileApp.use((req, res, next) => {
req.userId = "1234";
next();
});
mobileApp.tables.import('./tables');
mobileApp.api.import('./api');

Related

How to limit express api to only allow post requests coming from your client?

I am working on my first full stack application, specifically with the MERN stack, and have run into a bit of an issue. I am trying to implement a leaderboard stored in a db for a unity game on my website. I have everything working wherein the client can post and get scores from my MongoDB Atlas database using my Express api. However, in the case of a leaderboard, I need to insure that the scores can ONLY be sent by the client based on how the game goes. With the current working configuration, anyone can send spoof scores via the api without having to play the game.
I first thought was to try to implement JWT to authenticate that the api call was coming from the site, but in my head any auth token like JWT could still be copied down by a user and sent with spoofed scores easily with Postman.
I am not extensively familiar with databases and suspect that this could possibly be solved if I wasn't using a DBaaS provider like Atlas but I am not entire sure.
Any thoughts or recommendations would be greatly appreciated!
You could define a middleware function and check the method of the incoming request:
const allowOnlyPost = (req, res, next) => {
if (req.method !== 'POST') {
return res.status(401).send(`Method ${req.method} not allowed`)
}
next()
}
module.exports = { allowOnlyPost }
And then apply it to the routes you want to protect:
const { allowOnlyPost } = require('./your/middleware/folder')
app.use('/route/to/protect', allowOnlyPost, (req, res) => { ... })
An improvement to current answer's function could be:
const allowMethods = (...methods) => {
return (req, res, next) => {
if (!methods.map(m => m.toUpperCase()).includes(req.method.toUpperCase())) {
return res.status(401).send(`Method ${req.method} not allowed`)
}
next()
}
}
module.exports = { allowMethods }
So you could use it like this:
const { allowMethods } = require('./your/middleware/folder')
app.use('/route/to/protect', allowMethods('get','post'), (req, res) => { ... })

How can I respond the request from an authorization middleware in a Next.js api route?

Let's say I have the following Next.js api route.
/api/protected-api
This api will get a authorization: "Bearer: TOKEN" header for authorization purposes.
import { NextApiHandler } from "next";
const apiHandler: NextApiHandler = async (req, res) => {
await runAuthMiddleware(req,res);
// THE REST OF THE API LOGIC SHOULD ONLY RUN IF AUTHORIZATION SUCCEEDS
// IN THEORY, runAuthMiddleware WOULD RESPOND WITH 403 IF AUTHORIZATION FAILS
return res.json(data);
};
What I mean by the code above is:
If authorization fails, I would like to respond a 403 from the runAuthMiddleware function, and don't even bother running the rest of the code in the apiHandler.
Is this even possible? Is this an anti-pattern?
Should I got with something like this instead?
const apiHandler: NextApiHandler = async (req, res) => {
const authSuccess = await runAuthMiddleware(req,res);
if (authSuccess)
return res.json(data);
else
return res.status(403).send("Forbidden");
};
UPDATE:
It seems that there's no easy way of doing it. This package offers a possible solution: next-api-middleware
There is an easy way to do it if that is the only thing that you need, just make your own higher order function which checks auth:
const withAuth = (f) => async (req, res) => {
const isLogged = await checkIfUserIsLogged(req)
if (isLogged) {
return f(req, res)
} else {
return res.status(403).send("Forbidden");
}
}
const apiHandler = withAuth(async (req, res) => {
// This code now only runs of the user is logged
return res.json(data);
});
For more complex scenarios I would recommend to use https://github.com/hoangvvo/next-connect or something like that. But if you only need one middleware then it is completely fine to write your own.

What is the equivalent of express' res.sendStatus(200) on Next.js api serverless functions?

I was used to do the following in some of my express routes.
return res.sendStatus(200);
But the res object from NextApiHandlerType does not allow that method.
What would be the equivalent, in this case?
import { NextApiHandler } from "next";
const handler: NextApiHandler = async (req, res) => {
// DO STUFF
return res.??? // WHAT SHOULD I PUT HERE TO RETURN THE status CODE WITH THE STANDARD CODE MSG ?
};
I'm currently doing this, but it seems redundant.
return res.status(200).send("Ok");
From: http://expressjs.com/en/api.html
To anyone seeing this now, I was wondering the same thing. The docs aren't 100% clear IMO. This sends a status code and closes out the request.
res.status(200).end();
Here is what you can find in the documentation :
https://nextjs.org/docs/api-routes/response-helpers
The response (res) includes a set of Express.js-like methods to improve the developer experience and increase the speed of creating new API endpoints, take a look at the following example:
export default function handler(req, res) {
res.status(200).json({ name: 'Next.js' })
}
AFAIK, this is currently not possible inside a Next.js serverless function. I'm using "next": "10.1.3".
The closest alternative is, indeed:
return res.status(200).send("Ok");

Is it possible to use multiple .get on app.route?

app.route('/users')
.post(user.post)
.get(user.get)
.get(user.everyone)
.put(user.update)
.delete(user.delete);
I have ran into the problem of my function using two res.send, so I am getting the 'Error: cannot set header after they are sent.' error, to fix this I have turned it into two functions which I am trying to use two .get on the app.route, but it seems I can only use one as when I use two the second one doesn't work.
Is there a way I could use two .get on one app.route?
If not, what are my options to get around this problem?
You need to create separate routes for each api endpoint like this:
app.route('/users').get(req, res) => {
//Get all users
});
app.route('/users:/id').get(req, res) => {
//Get specific user
});
app.route('/users').post(req, res) => {
//Create new user
});
app.route('/users/:id').put(req, res) => {
//Update user
});
app.route('/users/:id').delete(req, res) => {
//Delete user
});
Once res.send is called, means your server has sent the response to the browser or whatever. you can't change the already sent response and its header.
You can use multiple callbacks on one route and one method(post,get)
An array of callback functions can handle a route. For example:
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/example/c', [cb0, cb1, cb2])
yes, you can use multiple HTTP requests either its .get or .post but with different params. or routes.

Angular 6 with steam-passport - Auth Guard Issue

I'm using steam-passport to loggin.
So basically, I go to localhost/auth/steam, this redirect me to steam service, then go back to localhost/auth/steam/return, and from there, I got my req.user as expected :
router.get('/auth/steam/return',
passport.authenticate('steam', { failureRedirect: 'http://localhost:4200/' }),
function(req, res) {
res.redirect('http://localhost:4200/'); --angular port application
console.log(req.user) -- I have all my datas
});
Again, when I open my brower and I go to localhost/api/isLoggedIn, I have my req.user as expected:
router.get('/api/isLoggedIn', (req, res) => {
if (req.isAuthenticated()) {
console.log(req.user)
if (req.user.db) {
res.json({user: req.user.db, success: true})
return
}
}
res.json({success: false})
})
The issue is when I'm using it with Angular.
I'm forced to do a window.location.href = "http://localhost:8080/auth/steam"; when I click on the loggin button. And again, I have my datas when the steam service answered to me.
But when I'm trying to access it from Angular:
isAuthenticated(): boolean {
let obs = this.http.get('http://localhost:8080/api/isLoggedIn').subscribe(data => {
return JSON.parse(data._body).success -- this is always FALSE!
})
}
How to manage the issue? From the brower, it's ok but from Angular, it's look like it's not the same guy who clicked on the button ahah.
Thanks for any future answer.
EDIT:
I invenstigate a bit, and I don't have the same session when I go over the brower to /api/isLoggedIn and when I make an http get request from Angular, how to link both?
session id for browser : EvbuWUZ7vceCxHsm7npb6572bLe-1lRC
session id for Angular : it change every time I make the request..
Your isAuthenticated() function is always returns undefined (which can be treated as false).
Look into your function. Your function is not returning anything. The return statement is inside of async function.
Try this.
isAuthenticated(): Observable<boolean> {
return this.http.get('http://localhost:8080/api/isLoggedIn')
.pipe(
map(data => !!JSON.parse(data._body).success)
)
}

Resources