I am pretty new to CORS. I am building a React App which simply posts data to a backend API. According to the API documentation I have to send a BASIC Authentication Header along with the request which is exactly what I am doing. The request works just fine when I send it through POSTMAN. But when I make the same request from my APP it says Invalid API Key. Below is my code:
App.js:
import React from 'react';
class App extends React.Component{
state = {
data: 'data'
};
handleClick = async () =>{
const res = await fetch('https://myapi.com/post',{
method: 'POST',
body: JSON.stringify({tp:'0'}),
mode: 'cors',
headers: {
content-type:'application/x-www-form-urlencoded',
Authorization : 'Basic ' + new Buffer('username:password').toString(base64)
}
});
const data = await res.json();
this.setState({data});
}
render() {
return(
<div>
<p>{this.state.data}</p>
<button onClick={this.handleClick}>Post</button>
</div>
);
}
}
I looked into the issue and found out that the headers are not being set when sending the request. When further digging into it I found out that the above request is not a simple request and hence the browser makes a preflight OPTIONS request to server. I do not know how the server is handling the requests but I think the server is not configured to handle the preflight OPTIONS. I might be wrong. I do not have any access to the server code. The same request through CORS Anywhere proxy and POSTMAN client is working fine but not while using the actual app. I used create-react-app to setup the boilerplate.
All I get is an Invalid API Token Error while sending request through the app.
Any help on how to get the headers through to the server would be appreciated.
According to another post, you might want to wrap the Authorization header in a Headers-object. I guess you should not really pay attention to the OPTIONS-request, that request shouldn't contain any user credentials and the server shouldn't really look for any credentials on a OPTIONS-request, more info.
What happens if you make the following changes (don't forget to npm install base-64).
import React from 'react';
const base64 = require('base-64');
class App extends React.Component{
state = {
data: 'data'
};
handleClick = async () => {
const headers = new Headers();
headers.append("Authorization", "Basic " + base64.encode("user:password"));
const res = await fetch('https://myapi.com/post',{
method: 'POST',
body: JSON.stringify({tp:'0'}),
mode: 'cors',
headers: headers
});
const data = await res.json();
this.setState({data});
}
render() {
return(
<div>
<p>{this.state.data}</p>
<button onClick={this.handleClick}>Post</button>
</div>
);
}
}
Related
Hello everyone it is been 6 hours I am struggling to solve this issue.
I have the following projects:
Client App: ReactJS using axios library
Server App: .NET Core Web api implementing JWT for authorization and authentication.
The Problem:
when trying to send get request from my react application using axios to the backend and attaching the jwt in the header I always get 401 unauthorized.
I tried the same way using postman It works perfectly !!!!!!!!!!
My attempts:
I tried to add the cors to my api and allows every origin, every header, every method still did not work.
Sending Request From ReactJS using axios:
async function getAllUserTasks() {
try {
return axios({
method: "get",
url: "http://localhost:5133/todo/ToDos",
headers: {
Authorization: `Bearer ${localStorage.getItem("jwtToken")}`,
},
body: {
userId: JSON.stringify('924BF80F-F394-4927-8DCC-A7B67AFA663C')
},
});
} catch (error) {
console.log(error);
}
}
//call the function one time
useEffect(() => {
getAllUserTasks();
}, []);
My config for the JWT in .NET app:
services.AddAuthentication(defaultScheme: JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.Issuer,
ValidAudience = jwtSettings.Audience,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(jwtSettings.Secret))
});
My config for policy and cors:
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.WithOrigins("http://localhost:3000", "http://localhost:3000/")
.AllowAnyMethod()
.AllowAnyHeader();
}));
This is really frustrating!
Try post request and also get the token from local storage outside of request definition. I think one of theese will fix your problem.
I've been working on a React/Spring project with the ambition of better understanding spring security and while going fairly successful thus far I've found a shortage of information relating to the handling of CSRF tokens between React and Spring boot. As such, I'm at an impasse.
My question is: How do you add and authenticate a CSRF token between React and Spring Boot on POST requests?
So far I've managed to get the CSRF token into my Cookies (thanks spring) and from there, I've attempted accessing the CSRF token and adding it to my HTTP headers although still receiving 403 responses on POST requests.
My spring security config class contains the declaration enabling CSRF outside of http(withHttpOnlyFalse() ).
How I'm trying to access the CSRF token:
I found this online previously for accessing the cookie:
function getCookie(name) {
if (!document.cookie) {
return null;
}
const xsrfCookies = document.cookie.split(';')
.map(c => c.trim())
.filter(c => c.startsWith(name + '='));
if (xsrfCookies.length === 0) {
return null;
}
return decodeURIComponent(xsrfCookies[0].split('=')[1]);
}
How I'm declaring HTTP headers:
let csrfToken = getCookie("XSRF-TOKEN");
console.log("testing csrf token: " + csrfToken);
const res = await fetch(`/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": csrfToken,
},
body: JSON.stringify({
firstName: firstName,
lastName: lastName,
mobileNumber: mobileNumber,
email: email,
password: password,
}),
});
Any help/support is greatly appreciated.
I've managed to resolve this.
Considering the difficulty I had sourcing information here's my solution:
Install the react-cookies library (npm install react-cookies)
Inside of the component which triggers the POST request, declare the following:
const cookies = useCookies(['XSRF-TOKEN']);
Pass 'cookies' to your function which facilitates the fetch request - For me this was simply called 'signUp' and was called inside my handleSubmit() method.
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
signUp(data.get("firstName"), data.get("mobileNumber"), data.get("email"),
data.get("password"), setUser, cookies['XSRF-TOKEN'] );
}
My fetch request inside of signUp() looks like the following:
await fetch(`/register`, {
headers: {
"X-XSRF-TOKEN": token,
"Content-Type": 'application/json'
},
credentials: 'include',
method: "POST",
body: JSON.stringify(customerData),
});
I'm sure this isn't the cleanest, nor the most practical way to do this and I hope someone is willing to shed further clarity if this is the case.
This was posted on the basis that I struggled to find a solution and hope this may be of some use/help going forwards.
The issue I am having is when trying to make a POST request I keep getting "Unauthenticated" error. This issue is because the api_token is not being passed.
If I make this request using PostMan it works.
Inside app.js I did a console.log(axios.defaults.headers.common) and that returns me the X-CSRF-Token & Authorization Bearer xxxx token.
Although, right before the axios call on the website (after submit), I added another console.log(axios.defaults.headers.common) and the only thing returned is Accept: 'application/json, text/plain, */*' which explains why the "Unauthenticated" error comes in, although I can't figure out why its correct in app.js but nothing get's passed after the fact. NOTE: I did not re-import axios in my component.
Inside my app.js file I have preset the headers for axios:
window.axios = require('axios')
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
}
let api_token = document.head.querySelector('meta[name="api-token"]');
if (api_token) {
console.log('api_token.content',api_token.content )
// THIS ABOVE RETURNS DATA CORRECTLY.
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + api_token.content;
}
Website - component after submit:
async submitForm () {
console.log('window.axios.default.headers.common', axios.defaults.headers.common)
// THIS ABOVE ^^ RETURNS EMPTY HEADERS
const res = await axios.post('/api/product/add/validate', this.form)
}
I managed to get Reddit OAuth to work and it is getting redirected to my homepage.
And I am getting a URL like http://localhost:3000/?state=XEA12&code=6p4pAyle2EWGVwIBlFJ6ERXjxKg
Now, when I try other APIs like /api/me. I am not able to get it working. I have also set the scope of my app to identity.
Here is the code snippet that I wrote:
import axios from "axios";
import useSWR from "swr";
const link = "https://www.reddit.com/api/v1/me";
const config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization: "bearer 6p4pAyle2EWGVwIBlFJ6ERXjxKg",
},
};
const fetcher = (url) => axios.get(url, config).then((res) => res);
export default function Home() {
const { data, error } = useSWR(link, fetcher);
if (error) return <div>failed to load </div>;
if (!data) return <div>loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}
Can you please tell me what I am doing wrong? Is it because of the headers or do I need to pass something else?
According to the documentation you need to retrieve access_token first, by using code param. Here is how to do that: https://github.com/reddit-archive/reddit/wiki/OAuth2#retrieving-the-access-token
Then you can use that access_token in a bearer auth. There is another note: API requests with a bearer token should be made to https://oauth.reddit.com, NOT www.reddit.com. Hope it will help
I have created react app using the npm module 'create-react-app'
I wanted to use external API for say api.example.com but was unable to call the external API because axios is requesting localhost rather than external API.
I tried the following Code:
class Example extends Component{
static defaultProps={
'url':"api.example.com"
}
handleChange(event){
axios.get(this.props.url+event.target.value)
.then(result=> console.log(result.data)
}
}
}
How to allow react app to access external API?
For example, POST request for added some Product in database:
In example I use JWT authentification for access at API.
JSON.stringify not necessary use, because Axios already implement this feature, here it is used for greater understanding. Don't use this on production!
const jwtToken = 'd70414362252a41ceger5re435gdgd45hjk';
const data = JSON.stringify({
id: '5',
title: 'product'
price: '15000',
description: 'string',
});
const configAxios = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer + ${jwtToken}`,
},
};
axios.post('https://api.somesite.com/products', data, configAxios)
.then((res) => {
this.date.description = res.data;
console.log(res);
})
.catch((err) => {
console.warn('error during http call', err);
});
It's also important to note that we strictly write the JWT token in the code, although it must be received periodically, this is not realized in this example.