Go Api returning Unauthorized - reactjs

i am new learner of GoLang+React. So that i started a project to learn. I made a RESTful Api with GoLang. Api Link. i made a login system with that api. And successfully i can login and set user data to sessionStorage. But the problem is when i am trying to logout a user by hit the logout endpoint of api with axios. First time it shows Unauthorized. and second time its showing Network Error.
Here is the Request code:
logout = () => {
const user = JSON.parse(sessionStorage.getItem('userData'));
const token = user.token;
const uid = user.id;
const url = "http://localhost:8000/logout"
axios.post(url,{"user_id":uid},{"Authorization":`Bearer ${token}`}).then((response) => response.json()).then((result) => {
let responseJson = result;
console.log(responseJson);
}).catch((error) => {
console.log(error);
})
}
Note: by client application i can logout successfully. But by axios i cant.

You need to provide auth headers under headers property of Axios config object:
axios.post(
url,
{ user_id: uid },
{ headers: { 'Authorization': `Bearer ${token}` } }
)
Explanation:
This is the axios post method signature, check docs:
axios.post(url[, data[, config]])
And the 3rd parameter config should have this interface:
{
...
baseURL?: string;
headers?: any; // this is for headers
params?: any;
....
}

I fixed that problem with adding this code to my package.json file
"proxy":"http://localhost:your_port"

Related

sessionStorage not available immediately after navigate

I am trying to implement an React solution with Strapi as backend where authorization is done using JWT-keys. My login form is implemented using the function below:
const handleLogin = async (e) => {
let responsekey = null
e.preventDefault();
const data = {
identifier: LoginState.username,
password: LoginState.password
}
await http.post(`auth/local`, data).then((response) => {
setAuth({
userid: response.data.user.id,
loggedin: true
})
responsekey = response.data.jwt
setLoginState({...LoginState, success: true});
sessionStorage.setItem('product-authkey', responsekey);
navigate('/profile');
}).catch(function(error) {
let result = ErrorHandlerAPI(error);
setLoginState({...LoginState, errormessage: result, erroroccurred: true});
});
}
The API-handler should return an Axios item which can be used to query the API. That function is also shown below. If no API-key is present it should return an Axios object without one as for some functionality in the site no JWT-key is necessary.
const GetAPI = () => {
let result = null
console.log(sessionStorage.getItem("product-authkey"))
if (sessionStorage.getItem("product-authkey") === null) {
result = axios.create(
{
baseURL: localurl,
headers: {
'Content-type': 'application/json'
}
}
)
} else {
result = axios.create({
baseURL: localurl,
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${sessionStorage.getItem("product-authkey")}`
}
})
}
return result
}
export default GetAPI()
However, once the user is redirected to the profile page (on which an API-call is made which needs an JWT-key), the request fails as there is no key present in the sessionStorage. The console.log also shows 'null'. If I look at the DevTools I do see that the key is there... And if I refresh the profile page the request goes through with the key, so the key and backend are working as they should.
I tried making the GetAPI function to be synchronous and to move the navigate command out of the await part in the handleLogin function, but that didn't help.
Does someone have an idea?
Thanks!
Sincerely,
Jelle
UPDATE:
Seems to work now, but I need to introduce the getAPI in the useEffect hook, I am not sure if that is a good pattern. This is the code of the profile page:
useEffect(() => {
let testapi = GetAPI()
const getMatches = async () => {
const response = await testapi.get(`/profile/${auth.userid}`)
const rawdata = response.data.data
... etc
}, [setMatchState]
export default GetAPI() this is the problematic line. You are running the GetApi function when the module loads. Basically you only get the token when you visit the site and the js files are loaded. Then you keep working with null. When you reload the page it can load the token from the session storage.
The solution is to export the function and call it when you need to make an api call.

Add default axios header after login nextjs

I'm using Next.js for my app, and currently have an API route that sets a JWT as a cookie. Throughout the app, I'm using Axios to fetch all of my data from external APIs, and after a user logs in I need to set that cookie as a default request header on every API call to make sure that a user has been authenticated. The basic flow is like this:
The login form sends a post request to my API route at /api/auth/login, passing the username and password and returning the JWT, and setting it as a cookie. Once the idToken cookie has been set I need to add that as an authentication header to every API request within my Axios instance, seen as adapter here. How can I go about getting this done?
My handle login function:
const handleLogin = async (values: ValuesProps) => {
const response = await axios.post('/api/auth/login', values);
if (response.status !== 200) {
throw new Error(response.statusText);
}
};
Which speaks to api/auth/login:
import { NextApiRequest, NextApiResponse } from 'next';
import { setCookie, parseCookies } from 'nookies';
import { adapter } from 'utils/api/config';
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'POST') {
res.status(500).json('Only POST requests allowed at this route.');
} else {
const { data } = await adapter.post(AUTH.login, JSON.stringify(req.body));
const cookies = parseCookies();
setCookie({ res }, 'idToken', data.token, {
maxAge: 30 * 24 * 60 * 60,
path: '/',
});
api.defaults.headers.Authorization = `Bearer ${cookies['idToken']}`
res.status(200).json(data);
}
};
export default handler;
As you see here I tried adding adapter.defaults.headers.Authorization as a global default, but I'm not seeing it in my request headers. What's the best way to go about setting this globally?
You could use axios.create. It is a factory that creates new instances of axios. So you write a function
import axios from "axios";
export const axiosInstance = async () =>{
// you need to be careful in next.js for adding cookies.
// You could be on the server or on client. this code will work for client assuming that you will be using on client side
// I belive you are using `parser` to get cookies. get the token
const yourToken="whatever"
const axiosClient = axios.create({
baseURL: 'baseUrlHere',
timeout: 1000,
headers: {
'Accept': 'application/vnd.GitHub.v3+json',
// this is how u set in your code
'Authorization': `Bearer ${cookies['idToken']}`
}
});
return axiosClient
}
Then import this in anywhere you want to use:
const {data}=await axiosInstance().post("/auth")
Technically this should work
You can set default header to all axios request by command:
const token = getCookie('token')
axios.defaults.headers.common["idToken"] = token

how to post headers with axios in react

Hi i have this problem:
i made and API with an auth JWT runs perfect and my front is in react so i need only one component its a simple app, so in my App.jsx i have my axios post to get the token and then i pass my token through the component, then i receive the props in the component and i saw the token but when i pass to the header like i test in postman, so nothing happens, and if i try the front and in the API i disable the JWT in my route works perfectly so i let my code next
const Cards = (props) => {
//console.log(props.auth.token);
//axios connection
const apiCall = async () =>{
let config = {
headers: {
'Authorization': `Bearer ${props.auth.token}`
}
}
console.log(config);
try {
const res = await clientAxios.post('/api/games', config,
{
console: 'nintendo',
game: 'super mario',
duration: '60hs'
},)
console.log(props.auth.token);
} catch (error) {
console.log(error.status);
}
}
apiCall();
Instead of sending the token with each request, set the token in axios' default headers like so:
window.axios.defaults.headers.common['Authorization'] = `Bearer ${jwtToken}`;

Axios request interceptor not working on browser refresh

I am using axios interceptor in my react app to pass the token for each request.
I initially call the setupAxiosInterceptors method after I login (See code below). This works perfectly fine until I refresh the browser.
const registerSucessfulLoginForJwt = (username, token) => {
sessionStorage.setItem(USER_NAME_SESSION_ATTRIBUTE_NAME, username)
setupAxiosInterceptors(createJwtAuth(token)) //Calling the axios interceptor at the time of login
}
See below the setupAxiosInterceptors method
const setupAxiosInterceptors = (token) => {
Axios.interceptors.request.use((config) => {
if(isUserLoggedIn()) {
config.headers.authorization = token
sessionStorage.setItem('authorization', token)
}
return config
})
}
Any thought on how to fix this so it works at all time?
I was able to find a solution to my problem. I create an ApiSetup.js file where I create a custom axios instance which could use for all requests.
const request = axios.create({
baseURL: API_PATH_BASE
})
request.interceptors.request.use(config => {
const currentUser = AuthenticationService.getLoggedInUser() //You can get the user directly from the cookie or session storage...
if(currentUser.userName) {
config.headers.Authorization = currentUser.userToken
}
return config
}, err => {
console.log(err)
return Promise.reject(err)
})
export default request

React-Adal returns 401 with POST request but 200 with GET request

I'm trying to send a POST request to an API that is hosted in Azure and is authenticated through Azure Active Directory. I'm using React with React-Adal to send my requests. I configured react-adal using the GitHub repo and this tutorial to guide me.
adalConfig.js
import { AuthenticationContext, adalFetch, withAdalLogin, adalGetToken } from 'react-adal';
export const adalConfig = {
tenant: 'ad5842d4-1111-1111-1111-111111111111',
clientId: '1f89aa20-1111-1111-1111-111111111111', //ClientID of the ReactClient application
endpoints: {
demoApi: 'e7926712-1111-1111-1111-111111111111', //ClientID of the DemoApi
microsoftGraphApi: 'https://graph.microsoft.com'
},
postLogoutRedirectUri: window.location.origin,
redirectUri: 'https://localhost:44394/',
cacheLocation: 'sessionStorage'
};
export const authContext = new AuthenticationContext(adalConfig);
export const adalDemoApiFetch = (fetch, url, options) =>
adalFetch(authContext, adalConfig.endpoints.demoApi, fetch, url, options);
export const adalTokenFetch = () =>
adalGetToken(authContext, adalConfig.endpoints.demoApi);
export const withAdalLoginApi = withAdalLogin(authContext, adalConfig.endpoints);
When I use the adalDemoApiFetch with a GET request it works fine and returns 200 with the list of schedules.
const url = `https://localhost:44322/api/Schedules/GetAllSchedules`;
const response = await adalDemoApiFetch(axios.get, url);
console.log(response);
const schedules = response.data;
When I use the same adalDemoApiFetch with a POST to add a new schedule to the list it returns a 401.
const url = `https://localhost:44322/api/Schedules/AddSchedule`;
const azureADID = authContext.getCachedUser();
const token = authContext.acquireToken("e7926712-1111-1111-1111-111111111111");
console.log(token);
const options = {
beginningDateTime: this.state.begDateTime.toJSON(),
endindDateTime: this.state.endDateTime.toJSON(),
userID: this.state.userID,
azureADID: azureADID.profile.oid
};
const response = await adalDemoApiFetch(axios.post, url, options);
console.log(response);
I also tried copying out the token and using it in Postman to make the call and it still returns 401. When I use the token that is returned from the function below it works just fine.
export const adalTokenFetch = () =>
adalGetToken(authContext, adalConfig.endpoints.demoApi);
I use axios to call it in the code below and it works just fine.
const url = `https://localhost:44322/api/Schedules/AddSchedule`;
const azureADID = authContext.getCachedUser();
const token = await adalTokenFetch();
console.log(token);
const options = {
beginningDateTime: this.state.begDateTime.toJSON(),
endindDateTime: this.state.endDateTime.toJSON(),
userID: this.state.userID,
azureADID: azureADID.profile.oid
};
const response = await axios.post(url,
{
data: options
},
{
headers: {
"Authorization": `Bearer ${token}`
}
}
);
console.log(response);
What am I doing wrong? Why would it work with a GET request and not with the POST request? Am I missing something?
I tried working with Axios too. Seems that using axios it is unable to authorize the bearer token. Try using the Adalfetch that fixed the problem for me.
You need to tell adalApiFetch you are using POST method instead of GET. It defaults to GET, that is why that works ootb. Use the options object.

Resources