React native Axios Django - Csrf failed referer checking failed no referer - reactjs

I am calling a Django back-end api from React front-end using axios.
For that api which is login api, I am using Django Knox package in logic.
React.js - I am calling axios.request(method, url, data) and the api call is working correctly.
When I went to Developer tools>Network, I can see Referer header set to React.js website in request header and no other csrf-related header. In Response headers I can see two set-cookie headers, csrftoken and sessionid.
React Native - same way I am calling api but api returns error csrf failed referer checking failed - no referer . When I checked response.config, Referer header is not set unlike React.js
Curl - works fine
httpie - works fine
How can I get rid of this error.
Note 1 - My Django back-end is based on api token logic and not csrf in any way.
Note 2 - React.js and Django are hosted on different domains. I am facing error in React Native which is in debug mode.
Update 1 - After disabling CSRF middleware in Django settings.py, now I am getting only one setCookie header (csrftoken is no longer obtained) but same error still persists.

Django Rest api need a Referer header.
In case of React.js it is automatically set (maybe by browser) and its value is current website.
But in case of React Native, it is not set. so we have to manually set it.
From this link, i set Referer header in axios. see below code
export const axiosAPICall = (method,url,data,headers) => {
let request = {
method: method,
url: url,
};
if (data) {
request['data'] = data;
}
if (headers) {
request['headers'] = headers;
}
// Referer is auto-set in react.js as same website value.
// for react-native we have to set it manually to target api:port
request['headers'] = {
...request['headers'],
Referer: url
}
return axios.request(request)
.then(res => res.data)
.catch(error => {throw error});
};
In Django settings.py, I commented CSRF middleware
In Django settings.py, I added only TokenAuthentication class to remove SessionAuthentication.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
Note - Please do steps 2 and 3 at your risk after knowing your requirements properly. I removed CSRF middleware because my API was completely dependent on token for auth. I did not need CSRF in any way.

Related

Flask cookies.get returning none on React fetch request even with 'credentials: "include"'

I've trying to make a fetch request from my React app to my backend Flask server that will user a token id saved in cookies.
I previously set the cookie and it shows in browser but when I try to make the request it shows that comes back with error saying it returned none
Front-end
fetch(url, {
credentials: 'include'
}).then((response) => ...
Back-end
#app.route('/cookie', methods=['POST', 'GET'])
def api_get_cookie():
print(request.cookies) // print empty dictionary
return request.cookies.get('token')

Why React can't reach Flask endpoints in production?

I've got a React app with Flask on the backend in production and I found out
that none of my endpoints are reached from React.
I'm aware that when using client-side routing developer needs to use a catch-all function
similar to the below:
#app.errorhandler(404)
def error_handler(e):
return render_template('index.html')
I'm using Flask-CORS to handle cross origin requests:
within config.py:
class ProductionConfig:
CORS_HEADERS = 'Content-Type'
...
...
my blueprint:
CORS(auth_blueprint, resources={r'/*': {"origins": "https://example.com", "allow_headers": "*", "expose_headers": "*"}})
#auth_blueprint.route('/auth/login', methods=['POST'])
#cross_origin()
def login():
...
...
on the frondend I'm defining headers like this:
const headers = { "Access-Control-Allow-Origin": "*" };
const url = "https://example.com:5000/auth/login";
axios.post(url, data, headers).then(resp => { ... })
And I'm not getting any errors whatsoever. Server's logs are clean and the console only shows Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://example.com:5000/auth/login. (Reason: CORS request did not succeed).
"Reason: CORS request did not succeed" means that the server didn't return anything.
The app renders fine however React (axios) can't reach my endpoints. Are there any gotchas I'm not aware of ? When request is sent I'm not even getting a status code in the network tab.
Thank you.
Screenshot of the network tab:
You need to change the connection protocol to http.

CORS error on Axios PUT request from React to Spring API

I am working on an update functionality using PUT. I have a React front end and Spring back-end API. Here is the following PUT request made from front-end:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {stuff})
}
Controller to handle this request:
#RestController
#CrossOrigin(origins="http://localhost:3000")
public class StuffController {
#Autowired
private StuffService stuffService;
#PutMapping(path="/stuff/{username}/{id}")
public ResponseEntity<Stuff> updateStuff(#PathVariable String username,
#PathVariable long id,
#RequestBody Stuff stuff) {
Stuff response = stuffService.save(stuff);
return new ResponseEntity<Stuff>(stuff, HttpStatus.OK);
}
I am able to use the same service for GET and DELETE. I am also able to send request using REST client. But when I am trying using browser I am getting this error in console:
Access to XMLHttpRequest at 'http://localhost:8080/stuff/abc' from origin
'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
PUT http://localhost:8080/stuff/abc net::ERR_FAILED
Not able to figure out why its just happening for PUT request? How to resolve this? Appreciate your help and time!
EDIT:
Updated the front-end to:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {
headers:{
'Access-Control-Allow-Origin':'*',
'Content-Type': 'application/json;charset=UTF-8',
}
})
}
Still its throwing the same error. So far Spring Security is not configured. I am just checking a simple update flow without any authentication or authorization.
EDIT 2: Request headers in browser has Access-Control-Allow-Origin: *:
I ran into a similar issue a while ago. Check if the variables of your model class in the backend have the same name as in your frontend. That fixed it for me.
The best way to deal with this cors policy is to add a proxy field in the pakage.json file.enter image description here
In reactjs application you can use your spring boot api's URL as proxy to avoid CORS issue.
package.
package.json
{
"proxy": "http://localhost:8080/",
"dependencies": {
.
.
.
}
}
axios
Axios.put(stuff/${username}, {stuff})

React App + Spring Boot - JWT auth token inside a cookie is not set in Chrome

I'm trying to configure Spring Boot to set-cookie containing JWT auth token following a sign-in request from my react app, and then the expectation is that the browser will automatically set this cookie to all requests as specified by the cookie path. The behaviour is ok on my friend's environment - same code, Chrome browser, different machine. I tried clearing node_modules, mvn clean install, also tried different browsers Chrome and FireFox, no success.
Here is the all the relevant code (let me know if I'm missing something else important)
React is running on localhost:3000
Spring Boot is running on localhost:8080
There is a proxy in the package.json
"proxy": "http://localhost:8080",
To test the auth flow we are issuing a sign-in request from the sign-in form (react), the request is successfully proxied to port 8080 and the response from the server is successfully returning the JWT token as part of an auth cookie. The cookie is specified to the /api path. Network request as seen in Chrome below:
Immediately after the login, the react app is issuing a second HTTP request to the back-end, but a break-point on the server shows no cookies are passed from the browser as part of this request. The request is to http://localhost:3000/api/user.
In the front-end we are using fetch to make that request and it looks like this:
fetch("/api/user, {
credentials: "same-origin"
})
Just for additional context this is how we return the original cookie from the server, upon a successful login:
#PostMapping("/signin")
public ResponseEntity signin(#RequestBody AuthenticationRequest data, HttpServletResponse response) {
try {
String username = data.getUsername();
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, data.getPassword()));
User user = (User) authentication.getPrincipal();
String token = jwtTokenProvider.createToken(user);
final Cookie cookie = new Cookie("auth", token);
cookie.setSecure(!environment.acceptsProfiles(Profiles.of("dev")));
cookie.setHttpOnly(true);
cookie.setMaxAge(Integer.MAX_VALUE);
cookie.setPath("/api");
response.addCookie(cookie);
return ok(buildUserResponseObject(user));
} catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid username/password supplied");
}
}
Is there anything wrong with our approach? What could be preventing my browser from passing on the auth cookie?
Oh this is embarrassing...
The issue was this line
cookie.setSecure(!environment.acceptsProfiles(Profiles.of("dev")));
!environment.acceptsProfiles(Profiles.of("dev")) was evaluating to true and it was causing the cookie to be only passed if the connection is secure, which it wasn't because it was localhost. Mystery solved.

Call Django API running on a server from Angular running locally

I am learning with Django and Angular.
I have setup a Django API back-end on on http://serverip:8666/athletics/
I have created a small Angular application that I am running from my local machine.
The following code in my Angular app:
$scope.list_athletes = function(){
console.log('hey');
$http
.get('http://serverip:8666/athletics/')
.success(function (result) {
console.log('success');
})
}
generates the error:
XMLHttpRequest cannot load http://serverip:8666/athletics/. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:65356' is therefore not allowed
access.
What causes this error? How can I resolve it so that I can access the Django API from my local Angular app?
The problem you're having is related to not having CORS enabled.
As a security policy, JavaScript can't make requests across domains while running in your browser. This is meant to prevent untrusted code from executing without the user's knowledge. The workaround is to enable CORS by white listing domains.
You need to set the Access-Control-Allow-Origin response header in your responses like so:
def my_view(request):
data = json.dumps({'foo':'bar'})
response = HttpResponse(data)
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:65356'
return response
This will enable CORS for your angular app. You can even add django-cors-headers to your project to have this functionality implemented for you. This can be added to any Django response object, such as django.http.repsonse.HttpResponse. Because you appear to be using a DRF Response object, you may need to use something like
return Response(serializer.data, headers={'Access-Control-Allow-Origin': 'http://127.0.0.1:65356'})
to set your response headers.
You should also check out this site for more information on how to enable CORS in your webapp.
Have you done the settings part in settings.py
INSTALLED_APPS = (
'corsheaders',
)
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
)
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:65356'
)
And also include CORS_ALLOW_CREDENTIALS, CORS_ALLOW_HEADERS settings

Resources