Have a front end nextJs running on a different port to the backend nestjs.
Within the nextJs session-cookie I have 2 JWT tokens access and refresh.
I can extract the access token from the next-auth session-token but axios will not send to nestjs.
If I use the { withCredentials: true } the whole next-auth token is sent but if I use the headers object nothing is received
const data = await axios.post(
process.env.NEXT_PUBLIC_SH_API_BASEURL + '/blog',
{ formData },
//{ withCredentials: true }
{
headers: {
Cookie:
'Authentication=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEzNTQ1N2FiLWI4MGUtNDU2OC1hY2RiLWNiODZmYTJlNGQxMyIsImlhdCI6MTY1MzU0NjM0NiwiZXhwIjoxNjU0NDQ2MzQ2fQ.fvnRXYwheuIOHvlTZRGqBiVR98JxdT7UqZbc6SAvcAk; Path=/; HttpOnly;'
},
}
);
nestJS - log when using with credentials
{
'next-auth.csrf-token': '493deccd24c0165f8afe08db04352415c46c7a6f150f9c51320aea0d5444589d|51953c1c056c986b799afb9dcea8c94469d35b4aab291b02ee343057fa80a70e',
'next-auth.callback-url': 'http://localhost:3000/auth/signin?callbackUrl=http://localhost:3000/',
'next-auth.session-token': 'eyJhbGc
}
But if use the headers I get
[Object: null prototype] {}
The nestJs logging is done using:
jwtFromRequest: ExtractJwt.fromExtractors([
(request: Request) => {
console.log('JWT strategy auth cookie');
console.log(request?.cookies);
return request?.cookies?.Authentication;
},
]),
If I make a call from postman there is no issue with processing the header cookie.
Could you let me know how to get axios to send the header cookie only?
Thanks
Related
I'm using a NestJS backend with a NextJS frontend, both hosted seperately.
NestJS Backend
I enabled CORS in the backend as follows:
app.enableCors({ credentials: true, origin: process.env.FRONTEND_URL });
When using cors-test.codehappy.dev to check the CORS headers everything looks good. All headers are present and the access-control-allow-origin header points to the right domain where the front-end is hosted on.
NextJS Frontend
On the NextJS frontend I'm using Axios to make request to the backend (the exact same url as used above).However, when creating a request the preflight request in Chrome is missing all CORS headers. The Axios instance below is imported when a HTTP request is needed.
import Axios from 'axios';
const api = Axios.create({
baseURL: process.env.BACKENDURL,
withCredentials: true
});
export default api;
The error in the console:
The preflight request:
in next.config.js
module.exports = {
//avoiding CORS error, more here: https://vercel.com/support/articles/how-to-enable-cors
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
},
}
I am in a next-js app and my auth token is stored in cookies.
For some raisons i use Swr and Api route to fetch my secured api backend.
i am trying to find a way to put my auth token in all api request.
During login cookie is set
res.setHeader(
'Set-Cookie',
cookie.serialize('token', data.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
maxAge: data.expires_in, // 1 week
sameSite: 'strict',
path: '/',
}),
);
This is an example of a page using swr fetch
//page/test.ts - example of my test route
const { data, error } = useFetchContent(id);
if (error) {
showError('error');
replace('/');
}
return <DisplayContent content={data} />
This is a swrFetchHook
// fetchContentHook
function useFetchContent(id: string): ContentDetail {
return useSWR<any>(`/api/content/${id}`, fetcherApiRoute);
}
const fetcherApiRoute = (url: string): Promise<any> => {
return axios(url)
.then((r) => r.data)
.catch((err) => {
console.info('error is ', err)
throw err
});
};
export default useFetchContent;
inside api route
export default async (req, res): Promise<ContentDetail> => {
const { id } = req.query;
if (req.method === 'GET') {
const fetchRealApi = await apiAxios(url);
if(fetchRealApi) {
// here depending on result of fetchRealApi i add some other fetch ...
return res.status(200).json({ ...fetchRealApi, complement: comp1 });
}
return res.status(500)
}
return res.status(500).json({ message: 'Unsupported method only GET is allowed' });
};
and finally api axios configuration
const apiAxios = axios.create({
baseURL: '/myBase',
});
apiAxios.interceptors.request.use(
async (req) => {
// HERE i am trying to get token from cookies
// and also HERE if token is expired i am trying to refresh token
config.headers.Authorization = token;
req.headers['Content-type'] = 'application/x-www-form-urlencoded';
return req;
},
(error) => {
return Promise.reject(error);
},
);
export default apiAxios;
I am stuck here because i cant find token during apiAxios.interceptors.request.use...
Did you know what i am doing wrong, and am i on a correct way to handle this behavior ?
To allow sending server cookie to every subsequent request, you need to set withCredentials to true. here is the code.
const apiAxios = axios.create({
baseURL: '/myBase',
withCredentials: true,
});
Nilesh's answer is right if your API is able to authorize requests based on cookies. Also it needs the API to be in the same domain as your frontend app. If you need to send tokens to the API (the one which is in the cookie), then you will need a small backend component often called BFF or Token Handler. It can extract the token from the cookie and put in an Authorization header.
At Curity we've created a sample implementation of such a Token Handler, of which you can inspire: https://github.com/curityio/kong-bff-plugin/ You can also have a look at an overview article of the Token Handler pattern.
I want to create a website with Svelte/Kit and use JWT.
I have found instructions on the internet, for example:
Svelte JWT Authentication https://morioh.com/p/1d95522418b2
SvelteKit Session Authentication Using Cookies https://www.youtube.com/watch?v=bG7cxwBMVag
But unfortunately no instructions for Svelte Kit and JWT. So I tried it myself.
The token is generated at the endpoint, but does not arrive on the page (or is not callable). I suspect that some setting in the headers is wrong, but can't figure out what is wrong. This is my highly simplified test environment:
(1) I call the endpoint login.js from the page index.svelte. For testing, I omit checking email and password and send JWT right back. Data arrives, but I don't see the JWT.
(2) The JWT should be sent to another endpoint. What is the best way to do this?
The "page" index.svelte (simplified):
<script>
let email="", password="";
const doLogin = async () => {
const response = await fetch("/auth/login", {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
credentials: 'include',
body: JSON.stringify({
email,
password
})
});
if (response.status == 200) {
const { done, value } =
await response.body.getReader().read();
await console.log("done, value=", done,
JSON.parse(new TextDecoder("utf-8").decode(value)));
await console.log("headers=", response.headers);
}
}
</script>
<h1>Welcome to MyAuth</h1>
<input type=email bind:value={email}/><br/>
<input type=password bind:value={password}/><br/>
<button on:click={doLogin}>Submit</button>
The "endpoint" login.js (simplified):
import jwt from "jsonwebtoken";
export function post(request, context) {
const token = jwt.sign({
data: { text: "test" },
"topsecret",
});
const response = {
status: 200,
headers: {
'content-type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: {
passwordOk: true,
}
};
return response;
}
The console shows:
done, value= false {passwordOk: true}
index.svelte:59 headers= Headers {}
index.svelte:44 Fetch finished loading: POST "http://localhost:3000/auth/login".
doLogin # index.svelte:44
I think you are mixing up the two major parts to authentication:
Requesting/sending credentials.
Using those credentials to access protected content.
Authorization: Bearer ${token} is normally sent from the (browser) client to the server to request access to protected content. So right now, your server is asking the client for permission. This doesn't make sense.
Instead, the login endpoint should send the token via:
Set-Cookie header in the login endpoint.
The body of the response (where passwordOk is).
Set-Cookie causes the browser to send this value as a cookie with every future request. The server can check for this cookie value before serving protected content. This can be more secure because you can send an HTTP only cookie.
If the token is sent in the body of the response to login the client should send the token in future requests with the Authorization: Bearer ${token} header. The server can then check for this header before serving protected content.
I have an API that has a JSON file, I gonna get information from that with Axios but it has Token and I don't know how can use it anybody can help me?
here it's API
https://api.nytimes.com/svc/movies/v2/reviews/picks.json
I try this but its didn't work and gave me error 401 and this
GET https://api.nytimes.com/svc/movies/v2/reviews/picks.json%E2%80%AC%E2%80%AC 401 (Unauthorized)
<script>
import axios from "axios";
export default {
data() {
return {};
},
methods: {
async getDataFromApi() {
const res=await axios.get("https://api.nytimes.com/svc/movies/v2/reviews/picks.json");
console.log(res.data)
},
},
};
</script>
please, someone helping me
401 Error means you not authenticated. you must add a token in axios authorization header and send it with your HTTP request.
const res = await axios.get('https://api.nytimes.com/svc/movies/v2/reviews/picks.json', {
headers: {
authorization: 'my secret token'
}
});
This is the hard code way, for more efficiency, you must define interceptors for axios to send the token with every HTTP request. see this: https://gist.github.com/srph/38f67a10e991b6cb2d83
I am developing an API with Sails.js and an user App with Ionic-React. At page load I make an axios request to get the _csrf token. When I submit the data from a login form to sails I always get a 403 Forbidden response. I disabled csrf (config/security.js) in sails and then I could retrieve the response. I am sending the token in the header.
I am trying too to get the session cookie but its not working I think that might be why the server refuses the request.
Ionic App:
componentDidMount(this: this) {
axios.get('http://localhost:1337/api/v1/security/grant-csrf-token')
.then(response => {
const _csrf = response.data._csrf
this.setState({
form: {
...this.state.form,
_csrf: _csrf,
}})
});
}
OnSubmit:
const { emailAddress, password, _csrf } = this.state.form;
const config= {
data: {
"emailAddress": emailAddress,
"password": password,
},
headers: {
"x-csrf-token": _csrf
},
withCredentials: true,
jar:cookieJar,
};
axios.post('http://localhost:1337/api/v1/users/authenticate', null, config)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})};
On Chrome DevTools Network Response:
On Postman this same request works and I get a 200 with the user data, and the request does include the sails.sid cookie.
I do not want to disable csrf protection, that wouldn't be a solution. Is it the sails.sid cookie that I am missing?
I am using this,
axios({
method: 'post',
crossdomain: true,
url: apiFormUrl,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
"Authorization": access_token
}
})
.then
and it works