How can I fix "CSRF token missing" error? - django

I'm building a web application with Django as my backend framework and DjangoRestFramework as webAPI, React Native as the frontend, and apisauce as an HTTP client. When I try to make a POST request from the frontend to the backend, I get this error :
CSRF Failed: CSRF token missing
I don't get the error when I use postman.
Is it good if I comment this out django.middleware.csrf.CsrfViewMiddleware ?

CSRF tokens are used to prevent cross-site request forgery attacks. This error implies that you are not providing CSRF in your POST request. I was wondering about your reason to use apisauce instead of axios, since axios automatic inclusion of the CSRF token.
Meaning you would not need to comment "django.middleware.csrf.CsrfViewMiddleware"
and ensure that your app is CSRF attack free.
EDIT:
Ok, if you must use apisauce, you can manual set the csrf token using following code:
import apisauce from 'apisauce';
const api = apisauce.create({
baseURL: 'https://yourbackend.com/api',
});
const csrftoken = getCookie('csrftoken');
api.setHeader('X-CSRFToken', csrftoken);
api.post('/endpoint', {
data: 'yourdata',
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
function getCookie(name) {
// you may have to change this function a bit
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}

Related

Flask POST requests fail when JWT_COOKIE_CSRF_PROTECT=True

My POST requests to flask backend only work with JWT_COOKIE_CSRF_PROTECT = False, but GET requests work
config:
CSRF_ENABLED = True
CORS_SUPPORTS_CREDENTIALS = True
JWT_TOKEN_LOCATION = ['cookies']
I access flask through axios from the Vue app
const path1 = `/limit_engine/balance`;
axios
.post(path1, { withCredentials: true })
.then((response) => {
console.log(response.data["balance"]);
})
.catch((error) => {
console.error(error);
});
https://flask-jwt-extended.readthedocs.io/en/stable/options/#jwt-cookie-csrf-protect
suggests JWT_COOKIE_CSRF_PROTECT should be always True in production, so I cannot keep it False then
Try to debug the request by examining headers. If you are sending requests from the browser, you can use any of Dev Tools (Chrome for example). Take a look at the Network tab, look for your POST request, find out which cookies are sent.
If you can't find CSRF token in the request then you should pass it from the backend to the frontend and keep it in cookies storage.
After whole morning having trouble with this I realized CSRF token is only read from request headers as seen here: https://flask-jwt-extended.readthedocs.io/en/stable/_modules/flask_jwt_extended/view_decorators/ not from cookies, so in Vue you need to manually append this header to your requests.
Relevant source code to add to your flask app and to your Vue app:
In flask app:
app.config['JWT_ACCESS_CSRF_HEADER_NAME'] = "X-CSRF-TOKEN"
app.config['JWT_REFRESH_CSRF_HEADER_NAME'] = "X-CSRF-REFRESH-TOKEN"
app.config['JWT_CSRF_IN_COOKIES'] = False
In your flask app login function:
from flask_jwt_extended import (
jwt_required, create_access_token,
jwt_refresh_token_required, create_refresh_token,
get_jwt_identity, set_access_cookies,
set_refresh_cookies, get_raw_jwt, get_csrf_token
)
new_token = create_access_token(identity=current_user.id, fresh=False)
new_refresh_token=create_refresh_token(identity=current_user.id)
response = jsonify({
'data': {
'message':'Ok',
'type': 'user',
'id': current_user.id,
'meta': {
'accessToken': new_token,
'access_csrf_token': get_csrf_token(new_token),
'refreshToken': new_refresh_token,
'refresh_csrf_token': get_csrf_token(new_refresh_token)
}
}
})
set_refresh_cookies(response, new_refresh_token)
set_access_cookies(response, new_token)
return (response)
In your Vue app in your login fuction "edit according if you use or not refresh token logic":
axios.defaults.headers.common['X-CSRF-TOKEN']=response.data.data.meta.access_csrf_token
axios.defaults.headers.common['X-CSRF-REFRESH-TOKEN']=response.data.data.meta.refresh_csrf_token
And lastly do the same in yout Vue TokenRefreshPlugin or the method you use
I guess there are more approaches like getting the CSRF headers from the cookies, but this one seems to work for me for now at least. The important point is adding this headers manually in Vue requests, because using axios.defaults.withCredentials = true is not enough.
Also check header includes csrf token in the requests as akdev suggests.
you can add csrf exception for request.
or follow:-
https://flask-jwt-extended.readthedocs.io/en/3.0.0_release/tokens_in_cookies/

Send a post request from an expressjs endpoint to django

I am trying to implement the following workflow.
Populate an html form
Submit it
The endpoint that is receiving the request(expressjs) does some processing and sends a request with the req.body to another backend(django)
Django returns a response to expressjs
The problem is that I am being stuck at the csrf level and more specifically getting this error:
invalid csrf token
403
ForbiddenError: invalid csrf token
Here is the code that I am using for the request:
router.post('/registration', function (req, res, next) {
axios.post('http://localhost:8000/register_extended/', JSON.stringify(req.body), {
'Content-Type': 'application/json'
}).then(() => {
console.log('success')
}).catch(() => {
console.log('failure')
})
res.send('respond with a resource');
});
});
and here are my middlewares
app.use(bodyParser.urlencoded({ extended: true }));
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(csrfMiddleware);
How can I provide a valid csrf token for my needs? Axios is supposed to the handling itself, thats why I chose it.
Django uses CSRF tokens to prevent CSRF attacks from untrusted domains. You can whitelist your site or IP where express is running to make post requests without a CSRF token. Add this to your Django 'settings.py':
CSRF_TRUSTED_ORIGINS = [
"yoursite.runningexpress.here.com"
]

VueJS Authentication with Django REST Key

I can retrieve a key after logging in through my Django REST API, but then I am wondering how I should store that key. I'm not really using Django, but I imagine I have to store the cookie myself then or something. I'm using Axios for VueJS to interact with the API. I am using django rest auth to get the token.
Keep it easy to Local Storage or SessionStorage after get token from Backend-Response and then pass it in every Request in Axios Header-config.
DRF auth Token get it from header with this format:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Add this section code to your Axios configs to get token from LocalStorage.
Axios.interceptors.request.use(
(config) => {
let token = window.localStorage.getItem("token");
if (token) {
config.headers["Authorization"] = `Token ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);

Generate CSRF Token in Ionic Framework

How to generate csrf token in ionic.?
i m using django framework as server and wish to post data to server.
This are my error:
Forbidden (403)
CSRF verification failed. Request aborted.
You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.
If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.
Help
Reason given for failure:
CSRF cookie not set.
Here are my code:
postRequest() {
var headers = new Headers();
headers.append("Accept", 'application/json');
headers.append('Content-Type', 'application/json');
let options = new RequestOptions({ headers: headers });
let body1 = {
site: this.selectedSite,
zone: this.selectedZone,
user: this.username,
categoryType: this.problemType,
conNo:'012-8888888'}
this.http.post("http://localhost:8000/apidb/simple_upload", JSON.stringify(body1), options)
.subscribe(data => {
resolve(data);
}, error => {
console.log(error);
});}
It doesn't look like your content type in the request is being set. You need to set it to 'applicatioon/json' and then it won't require CSRF

Populate a cookie with a Django csrf token

i need to understand something.
I've a rest server on server A (django-rest-framework). An app on server B (angularjs) requests the rest server.
I want to add authentication. each time i request http://serverA/api-auth/login/, it returns 403 because i don't pass the csrf token.
So, in my app.js, i've added :
.run(function($http, $cookies) {
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
});
now, fine, i can send the csrf token.
My question is, how can i populate the cookie ? Do i have to do a get() to obtain the token before posting ? Because currently my cookie is empty :(
Thank you
You cannot use SessionAuthentication method if you don't share the same domain. In your case the OAuth2Authentication is the way to go.
Assuming your angularjs code using jquery ajax to post, you can put the csrf token into the meta tag
<!--<meta name="csrf-token" content="{{csrf_token}}">-->
Then setup your jquery ajax method to include the csrf token.
jQuery(document).ajaxSend(function(event, xhr, settings) {
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
//var token = $('meta[name="csrf-token"]').attr('content');
var csrftoken = $.cookie('csrftoken');
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}..............
});