How to extend Auth0's middleware? - express

I'm trying to add some properties to the results of the authentication process. Auth0 sets up Express middleware like this:
export const checkJwt = auth({
audience: process.env.AUTH0_AUDIENCE,
issuerBaseURL: process.env.AUTH0_ISSUERBASEURL,
});
This checks the authorisation header and works fine. It creates an request.auth object and adds payload into that. Works.
However, I want to add details from my own database, such as an ID or an organisation the user belongs to.
I've tried multiple ways to capture the result of auth but just can't get my head around it.
export var newAuth = function (
req: Request,
res: Response,
next: NextFunction
) {
const opts = {
audience: process.env.AUTH0_AUDIENCE,
issuerBaseURL: process.env.AUTH0_ISSUERBASEURL,
};
return (req: Request, res: Response, next: NextFunction) => {
// is the issue here?
var result = auth(opts)(req, res, next);
return result;
}
};
I suppose I'm asking how can I intercept or extend middleware in Express?

Related

Access request body in ServerMiddleware in NUXT

Im building a simple interface to SeaTable. For security reasons, I'm not storing the DB and user keys in the code but instead set up a very lightweight API in NUXT using Server Middle wear. All is working as expected except for my login API endpoint.. I need to capture req.data but it's not available. All examples I have seen add body-phraser and Express. I don't wanna use express as I want to keep this as light as possible.
import fetch from 'node-fetch';
export default {
path: 'api/auth/login',
handler: async (req, res) => {
let requestOptions = {
method: "POST",
headers: {
"username": usr,
"password": psw
}
}
const url = 'https://MY_URL.com/api2/auth-token/'
const request = await fetch(url, requestOptions)
const data = await request.json()
res.end( JSON.stringify(data) )
}
}
I suppose since this call does not contain any keys i could just make the call on the front end capture the user token and send it to the backend to be stored. Id prefer not to expose even the URL to my seatable instance.

How to sign JSON responses in Express

I'm developing an Express.js server; since it manages sensible data, I'd like to add a cryptographic signature to every response, using a private key. The signature part is already OK, the problem is catching the JSON string just before is sent to the client to sign it.
Ideally I'd like to add a custom response header, e.g. X-signature, so clients could verify the received payload against the public key exposed by the service.
In Express, how can I intercept the response body after the JSON.stringify() call but before the headers are sent?
I've copied what is done in the compression() middleware, replacing the send() method of Response with my own and calling the original one after I calculate the signature. Here's a simplified solution just to show the concept, in the real word I've taken care of body's possible types. The fact that calculateSignature() is an async function is a little troublesome, but everything seems to work well now.
Any comment is appreciated!
import express, { RequestHandler } from 'express';
declare const calculateSignature = (payload: string) => Promise<string>;
const responseSignature = (): RequestHandler => (_, res, next) => {
const _send = res.send;
res.send = (body) => {
if (isPlaintextType(body)) {
calculateSignature(body)
.then((signature) => res.setHeader('X-Signature', signature))
.catch((e) => console.error(e))
.finally(() => _send.call(res, body));
return res;
} else {
return _send.call(res, body);
}
};
next();
};
const app = express();
app.use(responseSignature());
app.listen(3000);

How to implement silent token refresh with axios request interceptor?

We are implementing a token-based authentication and when a user signs in we generate access and refresh tokens then save that with the timestamp on device so we can later check if the access token is expired or not.
We are currently using axios interceptor before every request and checking if the token is still valid or not with the timestamp we saved earlier when we generated the access and refresh tokens, but when the access token is expired and we are making a request to refresh the token the app goes on an infinite loop and none of the requests go through (both the original and refresh token api requests). you can see my code below:
const instance = axios.create({
baseURL: 'http://localhost:8080'
});
const refreshToken = () => {
return new Promise((resolve, reject) => {
instance
.post('/token/renew')
.then(response => {
resolve('refresh successful');
})
.catch(error => {
reject(Error(`refresh fail: ${error}`));
});
});
};
instance.interceptors.request.use(
async config => {
const timestamp = 1602155221309;
const diffMinutes = Math.floor(Math.abs(Date.now() - timestamp) / 60000);
// if diffMinutes is greater than 30 minutes
if (diffMinutes > 30) {
const tokenResponse = await refreshToken();
return config;
}
return config;
},
error => {
return Promise.reject(error);
}
);
The infinite loop is caused by your interceptor triggering another Axios request on which said interceptor will also run and trigger another Axios request, forever.
A simple solution would be to make the refresh token network request using the default axios instance which doesn't include any interceptors:
const refreshToken = () => {
// You can skip returning a new `Promise` since `axios.post` already returns one.
return axios.post("YOUR_BASE_URL/token/renew");
};
Obviously that also means you'll have to write a bit of logic to send the current refresh token along if that's included in your instance interceptors.

Responding with a custom HTTP code with GraphQL Yoga from a mutation resolver

I'm working on a mutation resolver using GraphQL Yoga and using Prisma for my back-end. The mutation is for doing authentication and returning a JWT on successful login. The mutation currently looks like this:
loginEmployer: async (_, args, context, info) => {
const employer = await context.prisma.query.employer({
where: {
name: args.name,
}
})
const match = await bcrypt.compare(args.password, employer.hashedPassword);
if (match) {
return jwt.sign(employer, jwtSecret);
} else {
return "";
}
}
The algorithm is fairly simple as you can see: Find an employer with the matching name, compare the stored hashed password with the incoming using bcrypt, and return a signed jwt if there's a match. Pretty standard stuff.
However in the case there is no match, or if there is no employer matching the name, I'd like to respond with a 403. In express I'd simply do res.status(403).send({error: "No such username/password"}) but with GraphQL Yoga I'm a bit lost and couldn't find any documentation for how to do this.
Thanks for any replies sorting this out or pointing me in the right direction :)
Abhi from prisma here!
In GraphQL Yoga you can pass a context factory which contains the request and the response!
Here's an example!
new GraphQLServer({
typeDefs,
resolvers,
context: ({ req, res, ...rest }) => {
// pass things down in context!
return { req, res, userId: req.headers.userid };
},
})
Then in your resolver, just pull res out of the context object.
Now this does work fine and well, but here's a github issue on a similiar thing that had some other opinions on this: https://github.com/graphql/express-graphql/issues/71
Following #Lars Holdaas - It took me far too long to work out the answer. But the context parameters are request and response.
If you use req/res, it does not work. So a more accurate example:
new GraphQLServer({
typeDefs,
resolvers,
context: ({ request, response, ...rest }) => {
return {
req: request,
res: response,
userId: request.headers.userid
};
},
})

How do I design my Node.js API so that I can also consume it from the server side?

I have an API that returns some JSON from mongodb:
// In router.js
var api = require('api')
app.get('/lists', api.lists);
// In api.js
var db = require('db')
exports.lists = function(req, res) {
db.lists.find({}, function(err, lists) {
res.send(lists);
});
};
Is there a way to design the API so that I could also consume it from within my Node.js app? I'm trying to avoid having to duplicate any of the database code outside the API. I basically have a controller that can render the data server-side:
// In controller.js
var api = require('api')
exports.page = function(req, res) {
res.send(api.lists()); // This won't work
};
I found a hacky solution which was to pass a callback function to the api.lists(), but I have a feeling this is the "wrong" way to achieve this:
// In api.js
exports.lists = function(req, res, callback) {
db.lists.find({}, function(err, lists) {
if(callback){
callback(lists);
} else {
res.send(lists);
}
});
};
Any ideas?
I think the problem is that in your current code you are coupling your API to the response object. You can decouple them with something like this:
In router.js instead of using api.lists as the callback, define a function that will call api.lists with a callback that is wired to the response object. In this case api.list DOES NOT need to know about the response object but the function that we are creating does.
// In router.js
var api = require('api');
app.get('/lists', function(req, res) {
api.lists(function(err, lists) {
if(err) {
res.send('error page');
return;
}
res.send(lists);
});
});
In api.js we remove the reference to the response object. Now it will just call whatever callback it received with the appropriate data (err + lists). It's up to the callback to do whatever it pleases with the result.
// In api.js
var db = require('db')
exports.lists = function(callback) {
db.lists.find({}, function(err, lists) {
callback(err, lists);
});
};