How to use with credentials: true with TanStack Query fetch - credentials

Previously I used axios request withcredentials:true to get the cookie from server site when I started to to use useQuery of TanStack Query/react Query to fetch data, I couldn't be able to sent withCredentials: true. So I couldn't get any cookie from server site. Can anyone help me how to sent withCredentials when I'm fetching with useQuery of TanStack Query?
I have been tried to get answer that how to use React Query or TanStack query with Credentials.

React query doesn't perform any fetching, you can keep using axios.
const { data } = useQuery([some, key], async () => {
const { data } = await axios.get('SOME_URL', { withCredentials: true })
return data
}}

Related

Next-auth How to redirect when 401?

I am working with Next-auth and rtk query. I need that when a request, any, returns a 401 unauthorized error, the page redirects directly to the login. How is it done?
I added 'maxAge: 60' to the [...nextauth].js file and also refetchInterval={30} refetchOnWindowFocus={true} to the component tried to find a similar solution, but it doesn't work
since you're using rtk query, you can update your apiSlice baseQuery function, to check for auth errors and redirect on that, my suggestion is this:
create a base query where you check for the 401 and any other error you want:
// try to execute the req, if it fails logout, and redirect to login.
const baseQueryWithAuth: BaseQueryFn = async (args, api, extraOptions) => {
const result = await baseQuery(args, api, extraOptions);
if (result.error?.status === 403 || result.error?.status === 401) {
// non authorized, then redirect to login page.
// if we have jwt, here u should update the access token
localStorage.removeItem(TOKEN_KEY_IN_LOCAL_STORAGE);
Router.replace('/auth/login');
}
return result;
};
in the snippet above, when I'm referring to token deletion as logout because the token is already invalid in the DB, so I just need to delete it in the front, so no invalidate request is needed.
the mentioned baseQuery can be done like this:
const baseUrl = `${process.env.NEXT_PUBLIC_API_PROTOCOL}://${process.env.NEXT_PUBLIC_API_HOST}/api`;
const TOKEN_KEY_IN_LOCAL_STORAGE = 'SavedToken';
const baseQuery = fetchBaseQuery({
baseUrl,
// credentials: 'include',
prepareHeaders: (headers) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem(TOKEN_KEY_IN_LOCAL_STORAGE);
if (token) {
headers.set('Authorization', token);
} else {
Router.replace('/auth/login');
}
return headers;
},
});
and then now since you have a working base query with auth support, you can use that to create a main rtk query apiSlice for your project:
// create api
export const apiSlice = createApi({
baseQuery: baseQueryWithAuth,
tagTypes: ['tag1', 'tag2', 'tag3'],
endpoints: (_builder) => ({}),
});

Getting an empty object in Axios Get Request

I am trying to set up a get route using axios. I am using React. I am trying to get the state of user.
user.user logs:
{_id: '62c5bdda933b818e12bef350', username: 'JordanF', Profiles: Array(9), createdAt: '2022-07-06T16:52:42.396Z', updatedAt: '2022-07-09T19:24:10.523Z', …}
I am trying to display username on my page. But at the moment I can't even log the username to my backend, so won't be able to search my db.
Profile.jsx
function getUser(data) {
console.log(data)
axios({
url: `http://localhost:3000/profiles`,
method: "GET",
data: data
})
.then((response) => console.log(response))
}
useEffect(() => {
setProfileList(profiles)
getUser(user.user)
},[]);
Data logs the data in the front end that I would like to get in the backend
BackEnd Controller
I have tried a lot of different syntax for this, this is my most recent. In the backend temrinal my console.log hits, and req.body returns an empty object.
async function getUser(req,res){
console.log('getUser hit')
function log(){
console.log(req.body)
return req.body
}
await log()
}
Yup! I was being silly. GET requests are only really concerned with params. I changed my route, so that the User's ID was in the URL path, and used req.params.id and everything worked out!

Sending data from react to node by get request using axios library

for more than 3 hours I'm handling with an issue, what I'm trying to do is sending a get request from react to nodejs using axios library, I wanna pass some data into this request, as we know the get request don't have a body, so I've sent the data as query parameter like that
// base URL
const url = "http://localhost:8080/loginAsTeacher";
if(loginAs === "loginTeacher"){
axios.get(url,{
params :{
email: "abc123#gmail.com",
password: "abc1234*"
}
})
.then(res => console.log(res)) // this line return status:200 and data:null
.catch(err => console.log(err.message))
}
so this request success but the problem is the email and password are not passing to the backend
router.get("/loginAsTeacher", async (req,res)=>{
// values coming from the client
const loginEmail = req.params.email;
const loginPassword = req.params.password;
console.log(req.params); // this line return {} empty object
// get data of that user by his/her mail
const teacherData = await myModel.findOne({
email: loginEmail
}).exec()
res.status(200).json({
status: 200,
data: teacherData
})
})
the console.log above return an empty object, which means there's no parameters
Is this not the right solution ???
thanks for reading
To get your queries you need to get req.query instead of req.params
Btw. it's dangerous to send sensitive data over get. It could be get logged in plaintext even over https
use req.query instead of req.params. it will solve the issue

external api handling in the backend

On my express server I make queries to an external API using its own token. When I log in to my server I request a token to the external API based on the user who logged in, and I keep the token of the external API in the token of my express server.
Each user gets different data according to their token from the external api, for queries that require external API information, I read the received token and get the external API token to send it through headers with axios, for example:
const LoginUser = (request, response) {
axios.post('/ExternalApi/auth',request.body)
.then( data =>{
const payload = {
...
tokenExternalApi: data.token
}
const token = jwt.sign(payload, ...)
return response.status(200).json(token)
})
}
const getData = (req, response){
const tokenFromClient = req.headers.authorization
//Function extract tokenExternalApi from payload Token
const tokenExternalApi = getTokenExternl(tokenFromClient )
axios.get(`/urlExternalApi`, { headers:
{ Authorization: tokenExternalApi }}
).then(res => {
return response.status(200).json(res.data)
})
}
Is this the correct approach to managing external apis tokens or is there a cleaner way to do it?
Here is my sample code that I use for hit an external API within function in node js using axios
first time you should install axios npm install axois
const axios = require('axios');
async yourFunction(){
axios({
method: 'POST',
url: "http://yoururl.com",
data: {
name: '+62'+phoneNumber,
number: '+62'+phoneNumber,
message: 'success',
}
});
}
In my personal opinion, this seems to be a clean approach.
But keep in mind that tokens are visible to users, so the fact is your users can decode the token, view tokenExternalApi, know that you are using an external API in the backend and directly make calls to ExternalApi using that token, provided they have the know-how of it. If you understand this fact and are fine with it, then this works.
Otherwise, you can consider encoding the token before sending it to the user or store it on the server-side session.

How fix 'Error while running `getDataFromTree` Network error: localStorage is not defined'?

Everythings works but I keep getting: Error while running getDataFromTree Network error: localStorage is not defined. I tried conditionals to only send req from client but it did'nt work. All the requests seem to be coming from server.
I'm using google Oauth and passport for authentication in NextJS
Should I create authLink from a different file? Any clue?
Usefull links:
https://www.apollographql.com/docs/react/recipes/authentication/
https://github.com/zeit/next.js/tree/canary/examples/with-apollo
I've tried to conditional logic to only send req from client but then, logic stops working. Looks like most of nextJS reqest are from serverside.
let apolloClient = null
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? Bearer ${token} : "",
}
}
});
function create(initialState) {
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
const isBrowser = typeof window !== 'undefined'
console.log(isBrowser);
return new ApolloClient({
connectToDevTools: isBrowser,
ssrMode: !isBrowser, // Disables forceFetch on the server (so queries are only run once)
link: authLink.concat(new createHttpLink({
uri: 'http://localhost:3000/graphql', // Server URL (must be absolute)
credentials: 'same-origin', // Additional fetch() options like credentials or headers
// Use fetch() polyfill on the server
fetch: !isBrowser && fetch
})),
cache: new InMemoryCache().restore(initialState || {})
})
}
export default function initApollo(initialState) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (typeof window === 'undefined') {
return create(initialState)
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = create(initialState)
}
return apolloClient
}
I need apollo to send cookies with every request, so my react component can find if the user is logged in.
It's breaking my head, any help appreciated. Thank you in advance.

Resources