Access request body in ServerMiddleware in NUXT - vue.js

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.

Related

How to extend Auth0's middleware?

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?

OctoKit with Auth0 (Github Login) in NextJS

I am building a Next JS app that has Github Login through Auth0 and uses the Octokit to fetch user info / repos.
In order to get the IDP I had to setup a management api in auth0. https://community.auth0.com/t/can-i-get-the-github-access-token/47237 which I have setup in my NodeJs server to hide the management api token as : GET /getaccesstoken endpoint
On the client side : /chooserepo page, I have the following code :
const chooserepo = (props) => {
const octokit = new Octokit({
auth: props.accessToken,
});
async function run() {
const res = await octokit.request("GET /user");
console.log("authenticated as ", res.data);
}
run();
And
export const getServerSideProps = withPageAuthRequired({
async getServerSideProps({ req, params }) {
let { user } = getSession(req);
console.log("user from get session ", user);
let url = "http://localhost:4000/getaccesstoken/" + user.sub;
let data = await fetch(url);
let resData = await data.text();
return {
props: { accessToken: resData }, // will be passed to the page component as props
};
},
});
However, I keep getting Bad credentials error. If I directly put the access token in the Octokit it seems to work well, but doesn't work when it's fetching the access token from the server.
It seems like Octokit instance is created before server side props are sent. How do I fix it ?
I figured out the error by comparing the difference between the request headers when hardcoding and fetching access token from server. Turns out quotes and backslashes need to be replaced (and aren't visible when just console logging)

Invalid csrf token with NestJS

I would like to implement Csrf protection with NestJS and Quasar.
But I think I misunderstand something...
btw I'm not doing SSR, so I don't send the form from the back to the view.
Here is the NestJs back-end code:
async function bootstrap() {
const PORT = process.env.PORT;
const app = await NestFactory.create(AppModule, {
cors: true,
bodyParser: false,
});
console.log(`your App is listening on port ${PORT}`);
// Added Cookie-parser to user csurf packages
// Prevent CSRF attack
app.use(cookieParser());
app.use(csurf({ cookie: true }));
await app.listen(PORT);
}
bootstrap();
So I'm just using CookieParser and csurf package.
On my login page I call a "csrf endpoint" just to send a cookie to the view, to send it back with the post call (login).
I still get the "invalid csrf token" AND a CORS error and don't know why....(see screen below), any suggestions to make it works ?
When I try to login, error in the browser:
And error in the back-end:
Same error if I try a request with insomnia.
I thought that the CSRF token is attached to the "web browser" to go back to the back-end with nest request, so why I'm still getting this error ?
Insomnia send the cookie automatically with the right request so the token should go back to the back-end.
Any idea ?
Regards
EDIT:
After many times reading docs, It seems that CSRF protection is for SSR only ? No need to add csrf security with SPA ? Could anyone can confirm ?
EDIT: Here's another work:
The purpose here is to send a request before login to get a csrf token that I can put into a cookie to resend when I login with a POST method.
Here is my endpoint:
import { Controller, Get, Req, Res, HttpCode, Query } from "#nestjs/common";
#Controller("csrf")
export class SecurityController {
#Get("")
#HttpCode(200)
async getNewToken(#Req() req, #Res() res) {
const csrfToken = req.csrfToken();
res.send({ csrfToken });
}
}
Here is what I've done into my main.ts file (I'll explain below):
async function bootstrap() {
const PORT = process.env.PORT;
const app = await NestFactory.create(AppModule, {
cors: {
origin: "*",
methods: ["GET,HEAD,OPTIONS,POST,PUT"],
allowedHeaders: [
"Content-Type",
"X-CSRF-TOKEN",
"access-control-allow-methods",
"Access-Control-Allow-Origin",
"access-control-allow-credentials",
"access-control-allow-headers",
],
credentials: true,
},
bodyParser: false,
});
app.use(cookieParser());
app.use(csurf({ cookie: true }));
console.log(`your App is listening on port ${PORT}`);
await app.listen(PORT);
}
bootstrap();
And here my axiosInstance Interceptors of the request in my VueJS frontend:
axiosInstance.interceptors.request.use(
(req) => {
const token = Cookies.get('my_cookie')
if (token) {
req.headers.common['Authorization'] = 'Bearer ' + token.access_token
}
req.headers['Access-Control-Allow-Origin'] = '*'
req.headers['Access-Control-Allow-Credentials'] = 'true'
req.headers['Access-Control-Allow-Methods'] = 'GET,HEAD,OPTIONS,POST,PUT'
req.headers['Access-Control-Allow-Headers'] =
'access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,content-type,x-csrf-token'
const csrfToken = Cookies.get('X-CSRF-TOKEN')
if (csrfToken) {
req.headers['X-CSRF-TOKEN'] = csrfToken
console.log(req)
}
return req
},
(err) => {
console.log(err)
},
Here the same for repsonse:
axiosInstance.interceptors.response.use(
(response) => {
if (response?.data?.csrfToken) {
const {
data: { csrfToken },
} = response
Cookies.set('X-CSRF-TOKEN', csrfToken)
}
return response
},
And inside my login I make a call on the mounted function of my login component:
async mounted() {
const result = await securityService.getCsrf()
},
So now to explain:
As I said I'm not building a SSR project, that's why I want to send the token into a classic axios reponse and store it in a Cookie (this part is for test I heard that storing a csrf token into a classic cookie is not the right way.)
And for each next request I get the csrf token and "attach" it to the request into the headers, making my headers "custom".
Here is a problem I don't know how to make custom headers works with nestJS and CORS, that's why I try many thing with CORS options in NestJS and writte some custome header before the request go to the back-end but without success, I've got the same error message:
I'm a bit confuse about this problem and CORS/CSRF is a big deal for spa, my questions still the same, with CORS and SameSite cookie attributes, and my api is in a subdomain of my front-end, is it really necessary to make a anti-csrf pattern ?
Btw how can I make my custom headers working and why CORS say to me there is no "Access-Control-Allow-Origin" header but there is:
try to generate csrf token and pass to front on each petition
// main.ts - from NestJs - Backend
// after app.use(csurf({ cookie: true }))
app.use((req: any, res: any, next: any) => {
const token = req.csrfToken()
res.cookie("XSRF-TOKEN", token)
res.locals.csrfToken = token
next()
})
from: https://github.com/nestjs/nest/issues/6552#issuecomment-1175270849

K6 - Authentication - Get Auth Token

I have a mocha javascript file in which I have require function to login to the application in headless browser mode, login using the crendentials and return the jwt authentication.
I want to call this script through K6. But as I understand, calling node module java script from K6 is not possible?
Is there an alternative to this?
I have also just started implementing k6 and had same step to do ;)
Here is how I have done it.
you need to know how to authenticate to the API you want to use. I assume we have it, as you wrote you want to use node modules.
second, use appropriate method to communicate with API
next, catch token and append it to next requests headers
finally, test API with requests you want
I found code snippets on web page with k6 samples for APIs.
I have shorten a bit, sample code and end up with:
import {
describe
} from 'https://jslib.k6.io/functional/0.0.3/index.js';
import {
Httpx,
Request,
Get,
Post
} from 'https://jslib.k6.io/httpx/0.0.2/index.js';
import {
randomIntBetween,
randomItem
} from "https://jslib.k6.io/k6-utils/1.1.0/index.js";
export let options = {
thresholds: {
checks: [{
threshold: 'rate == 1.00',
abortOnFail: true
}],
},
vus: 2,
iterations: 2
};
//defining auth credentials
const CLIENT_ID = 'CLIENT_ID';
const CLIENT_SECRET = 'CLIENT_SECRET';
let session = new Httpx({
baseURL: 'https://url.to.api.com'
});
export default function testSuite() {
describe(`01. Authenticate the client for next operations`, (t) => {
let resp = session.post(`/path/to/auth/method`, {
//this sections relays on your api requirements, in short what is mandatory to be authenticated
grant_type: GRANT_TYPE,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
});
//printing out response body/status/access_token - for debug
// console.log(resp.body);
// console.log(resp.status);
// console.log(resp.json('access_token'));
//defining checks
t.expect(resp.status).as("Auth status").toBeBetween(200, 204)
.and(resp).toHaveValidJson()
.and(resp.json('access_token')).as("Auth token").toBeTruthy();
let authToken = resp.json('access_token');
// set the authorization header on the session for the subsequent requests.
session.addHeader('Authorization', `Bearer ${authToken}`);
})
describe('02. use other API method, but with authentication token in header ', (t) => {
let response = session.post(`/path/to/some/other/post/method`, {
"Cache-Control": "no-cache",
"SomeRequieredAttribute":"AttributeValue"
});
t.expect(response.status).as("response status").toBeBetween(200, 204)
.and(response).toHaveValidJson();
})
}

How to fetch data from an external api (Heroku) with Next JS?

I'm currently developing a web application with its server and the web application deployed separately. I've deployed my server and the database on Heroku, whilst I used Vercel to deploy my Next JS application.
My problem is when I make a request from Vercel using isomorphic-unfetch, it adds the address of my application in the request (https://myapp.vercel.app/myapp.herokuapp.com/). I only want http://myapp.herokuapp.com to be the request.
This is how I wrote the code for it.
import fetch from 'isomorphic-unfetch'
const host = process.env.API_ENDPOINT -- in this case, it was myapp.herokuapp.com
const myFunction = async(data) => {
const request = host.concat('/postSomething');
const res = await fetch(
request,
{
body: JSON.stringify({
variableA: data.variableA,
variableB: data.variableB
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
}
);
return await res.json();
}
Apparently, it was just a syntax error in my next.config.js file.
I included 'https://' before 'myapp.herokuapp.com' when I declared the API_ENDPOINT, and now it works.