401 error while uploading file to Sharepoint 2013 using REST API - sharepoint-2013

I have a simple html form where i have request is built to upload a file to Sharepoint Server 2013 using REST ( taken reference of the Code from the net ) .
Following is the code snippet
<html>
<head>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>
<script>
function AddAttachments()
{
var digest = "";
$.ajax(
{
url: "http://vmjnjlabeling01:22216/as/Shared Documents/_api/contextinfo",
method: "POST",
headers: {
"ACCEPT": "application/json;odata=verbose",
"content-type": "application/json;odata=verbose",
"Authorization" : "Basic c3AyMDEzOlNoYXJlcG9pbnRAMjAxMw=="
},
success: function (data) {
digest = data.d.GetContextWebInformation.FormDigestValue;
},
error: function (data) {
}
}).done(function() {
var fileInput = $('#uploadFile');
var fileName = fileInput[0].files[0].name;
var reader = new FileReader();
reader.onload = function (e) {
var fileData = e.target.result;
var res11 = $.ajax(
{
//url: "http://vmjnjlabeling01:22216/as/_api/web/lists/getbytitle('DocTest')/items(1)/AttachmentFiles/ add(FileName='" + fileName + "')",
url:"http://vmjnjlabeling01:22216/as/_api/web/getfolderbyserverrelativeurl('/as/Shared Documents')/Files/add(overwrite=true, url='" + fileName + "')",
method: "POST",
binaryStringRequestBody: true,
data: fileData,
processData: false,
headers: {
"ACCEPT": "application/json;odata=verbose",
"X-RequestDigest": digest,
// "content-length": fileData.byteLength
},
success: function (data) {
},
error: function (data) {
alert("Error occured." + data.responseText);
}
});
};
reader.readAsArrayBuffer(fileInput[0].files[0]);
});
}
</script>
</head>
<body>
<div>
<input id="uploadFile" type="file">
</div>
<div>
<input type="submit" onclick="AddAttachments()" value="Add Attachments"> </input>
</div>
</body>
</html>
But when i upload the document i am getting the 401 Error everytime despite all permissions have been given .
Please find the screenshot :
Any help on this topic to resolve this issue is most appreciated.
Regards,
N

You need to enable Basic Authentication credentials are sent in clear text in Authentication Providers.
Goto
Central Admin>> Security>>Security Authentication providers>>
In Right side dropdown select the Application and click on default
Tick Basic Authentication in Claims Authentication Types

Because your page isn't inside SharePoint (you're not getting any "SharePoint" in it), you'll need to authorize differently than if it were a SharePoint page. The easiest answer is probably to look at how the Add-in model works. On the other hand, since there's nothing going on in the page other than your attempt to upload an attachment, could the page be a SharePoint page?

Related

how to set cookies during vuejs post

I am trying to send post data to a django Restful API using vuejs. here is the code I have so far:
<script>
import axios from 'axios'
import VueCookies from 'vue-cookies'
//3RD ATTEMPT
VueCookies.set("csrftoken","00000000000000000000000000000000");
// # is an alias to /src
export default {
name: "Signup",
components: {},
data: () => {
},
methods: {
sendData(){
// 2ND ATTEMPT
// $cookies.set("csrftoken", "00000000000000000000000000000000");
axios({
method: 'post', //you can set what request you want to be
url: 'https://localhost:8000/indy/signup/',
data: {
csrfmiddlewaretoken: "00000000000000000000000000000000",
first_name: "wade",
last_name: "king",
email: "wade%40mail.com",
password1: "05470a5bfe",
password2: "05470a5bfe"
},
// 1ST ATTEMPT
// headers: {
// Cookie: "csrftoken= 00000000000000000000000000000000"
// },
withCredentials: true
})
}
}
</script>
I have a button which executes the sendData() method on a click. The code uses the axios library to send a post request to the django API running on http://localhost:800/indy/signup/
The problem with just sending a post request to the API is that it will get blocked in order to prevent Cross Site Response Forgery (CSRF), I dont quite understand CSRF but I know if the csrftoken is set as a cookie and has the same value as the csrfmiddlewaretoken then the post should go through to the API.
You can see my attempts to set the cookie in the code I provided
1ST ATTEMPT)
headers: {
Cookie: "csrftoken= 00000000000000000000000000000000"
},
Here I'm trying to set the cookie directly in the header. When I click send I get an error in my browser console saying refused to set unsafe header "Cookie"
2ND ATTEMPT)
$cookies.set("csrftoken", "00000000000000000000000000000000");
Here I'm trying to set the cookie using the vue-cookies module. When i click send I get the following error, net::ERR_SSL_PROTOCOL_ERROR
3RD ATTEMPT)
VueCookies.set("csrftoken","00000000000000000000000000000000");
Here I'm trying to set a global cookie using the vue-cookies module. When I click send I get the same error as attempt 2
IMPORTANT:
However when I send post data to the API from my terminal using the following curl command, it works perfectly
curl -s -D - -o /dev/null \
-H 'Cookie: csrftoken= 00000000000000000000000000000000' \
--data 'csrfmiddlewaretoken=00000000000000000000000000000000&first_name=wade&last_name=king&email=wade%40mail.com&password1=05470a5bfe&password2=05470a5bfe' \
http://localhost:8000/indy/signup/
my main question is How can I replicate this curl request using vuejs? I've looked all over on line and none of the tutorials deal with setting cookies.
I posted this question some time ago, I have managed to work around it by running the vue frontend on the same network as the django backend. Follow this tutorial for instructions: integrating vuejs and django
Once I had the application set up I was able to set the cookies much more cleanly using :
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
Here is my login page for example
<template>
<div class = "container">
<h2>Sign In</h2>
<b-form v-on:submit.prevent="submit()">
<b-form-group id="signin" label="">
<!-- dynamic error message -->
<p class="loginErr" v-if="logErr">Incorrect Username or Password</p>
<b-form-input
id="signin-email"
v-model="username"
placeholder="Email"
required
></b-form-input>
<b-form-input
id="signin-password"
v-model="password"
placeholder="Password"
required
type="password"
></b-form-input>
</b-form-group>
<b-button v-if="!loading" type="submit" variant="primary">Submit</b-button>
<b-spinner v-if="loading"></b-spinner>
</b-form>
</div>
</template>
<script>
import axios from 'axios'
import Vue from 'vue'
export default {
data: ()=>{
return{
loading: false,
logErr: false,
username:'',
password:'',
next: '%2Findy%2Fprofile%2F'
}
},
created: function(){
},
methods: {
submit(){
var vm = this;
vm.loading = true;
var dataStr = 'username='+vm.username+'&password='+vm.password
//set the csrf tokens so django doesn't get fussy when we post
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
axios.post('http://localhost:8000/api/signin/', dataStr)
.then(function (response) {
vm.loading = false;
//determine if indy accepts the login request
var res = response.data
console.log(response.data)
if(!res.login){
vm.logErr = true;
}else{
vm.redirect('home');
}
})
.catch(function (error) {
//currentObj.output = error;
});
},
redirect(path) {
this.$router.push('/' + path);
}
}
}
</script>
<style>
.loginErr{
color: orange;
}
</style>

Cannot upload more than 50KB using Google Cloud Storage POST Object XML API

I have created a form for uploading files to Google Cloud Storage using the POST Object XML API.
This works fine except for files exceeding 50KB. I have tested on Google Chrome and Firefox.
Here is the HTML
<form id="upload-form"
method="POST"
role="search">
<div class="form-group">
<label class="col-sm-2 control-label">File input</label>
<div class="col-sm-10">
<input type="file" class="filestyle"
name="file">
</div>
</div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button type="submit" class="btn btn-primary">Upload</button>
</div>
</div>
</form>
Here is the JavaScript
$(function () {
$('#upload-form').submit(function (e) {
e.preventDefault();
$.post("/experimental/upload/signed-url").then(function (info) {
var form = $('#upload-form')[0];
var formData = new FormData(form);
formData.append('googleAccessId', info.googleAccessId);
formData.append('policy', info.policy);
formData.append('signature', info.signature);
formData.append('bucket', info.bucket);
formData.append('key', info.key);
formData.append('success_action_status', info.successActionStatus);
$.ajax({
url: info.url,
data: formData,
type: 'POST',
contentType: false,
processData: false,
}).then(function (res2) {
console.log(res2);
});
});
});
});
This endpoint /experimental/upload/signed-url creates responses like this one
{
"googleAccessId" : "xxxx",
"policy" : "REDACTED",
"signature" : "REDACTED",
"successActionStatus" : "201",
"url" : "https://storage.googleapis.com/my-bucket",
"bucket" : "my-bucket",
"key" : "path/file-name",
"clientName" : null,
"publicUrl" : "https://storage.googleapis.com/my-bucket/path/file-name"
}
The code that creates the signature looks like this
try {
byte[] policy = policyDocument.toJsonBytes();
System.out.println(policyDocument.toJson());
String encodedPolicy = BaseEncoding.base64().encode(policy);
ServiceAccountCredentials cred = ServiceAccountCredentials
.fromStream(new FileInputStream(googleCredentialsFile));
byte[] signatureBytes = cred.sign(encodedPolicy.getBytes(Charsets.UTF_8));
String signature = BaseEncoding.base64().encode(signatureBytes);
info.setGoogleAccessId(cred.getAccount());
info.setPolicy(encodedPolicy);
info.setSignature(signature);
info.setSuccessActionStatus(STATUS_CODE);
info.setUrl(String.format(END_POINT_URL_FORMAT, info.getBucket()));
return info;
} catch (IOException e) {
throw new RuntimeException(e);
}
And here is what the policy document looks like
{
"conditions": [
{
"success_action_status": "201"
},
{
"bucket": "XXXXX"
},
{
"key": "path/file-name"
},
[
"content-length-range",
0,
1895825408
]
],
"expiration": "2018-06-13T12:51:45.143+03:00"
}
For files exceeding 50 KB, I get a HTTP status 400 with this body
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidArgument</Code>
<Message>Invalid argument.</Message>
<Details>Cannot create buckets using a POST.</Details>
</Error>
Is there anyone who can help me upload more than 50KB with this?
I am with GCP Support. We were able to get the same error message using a POST request based on this documentation, independently of the file size.
It got fixed once we changed the equivalent to "url" : "https://storage.googleapis.com/my-bucket", by adding the object: "url" : "https://storage.googleapis.com/my-bucket/my-file.ext",
Then using POST we kept getting some error messages so we changed the method to PUT. Then it worked.
Not working curl request:
curl -d #[FILENAME.EXT] #[JSONFILE.json] -X POST -H 'Authorization: Bearer [TOKEN]' http://[BUCKET_NAME].storage.googleapis.com/
Working curl request:
curl -v H 'Authorization: Bearer [TOKEN]' -F upload=#[FILENAME.EXT] -X PUT http://[BUCKET_NAME].storage.googleapis.com/[FILENAME.EXT]
I asked also to improve the documentation with the lessons learned.
Make your file field the last field of the form i.e.
var frm = new FormData(this);
var file_path = uploadForm.get("file");
uploadForm.delete("file");
uploadForm.append("file", file_path);
ajax.send(uploadForm);

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

I have created an API in Django, and some plain files from the desktop for angular and html. I like to fill an angular app with the API output. The request reaches the webserver, but then i get an error.
I get the following error: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
So i need to add "Access-Control-Allow-Origin" = True or something, but where and how? I have read many issues now, tried different things where and how to add, but i cannot figure it out. Can someone please help me with this? Thanx in advance.
views.py
def myjson(request):
data = Dish.objects.all()
#data = {'string':'test', 'twee':'pollo'}
#data = serializers.serialize('json', data)
data = json.dumps( [{'name': o.name, 'description': o.description, 'persons': o.persons} for o in data])
return HttpResponse(json.dumps(data),mimetype="application/json")
script.js
var myApp = angular.module('myApp', []);
myApp.controller('UserCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.dish = {};
//$scope.dish = [{"persons": 4, "name": "Pasta Bolognese", "description": "Pasta met een saus op tomaten basis"}, {"persons": 2, "name": "Pasta Carbonara", "description": "gdsdgfgds"}, {"persons": 4, "name": "Pizzadeeg voor Big Green Egg", "description": "sdgfgfdgfd"}, {"persons": 2, "name": "Low and Slow Ribs", "description": "fdsfsdsfdfsddf"}];
//$scope.dish = '';
$http({
method: 'GET',
url: 'http://127.0.0.1:8000/food/myjson/'
})
.success(function (data) {
// See here, we are now assigning this username
// to our existing model!
$scope.dish = data;
})
.error(function (data, status, headers, config) {
});
}]);
html
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular-route.js"></script>
<script src="script.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="UserCtrl">
{{ dish }}
</div>
</div>
</body>
</html>
This is a CORS (cross-origin resource sharing) issue. It happens when you try to hit an endpoint that is on a different domain. So that'd make sense if you have a REST API for your backend.
Your API needs to set headers to allow requests from various sources. We had to allow Access-Control-Allow-Origin to allow localhost for our dev environments. I found that in Angular, with each request, you need to send withCredentials: true as well.
$http({withCredentials: true, method: 'GET', url: http://127.0.0.1:8000/food/myjson/' })
.success(function (data) {
// See here, we are now assigning this username
// to our existing model!
$scope.dish = data;
})
.error(function (data, status, headers, config) {
});
});
Some sources say you also need to set the header on the client side as well for each request. I haven't had to do that though. But it may not hurt to include it:
headers: {'Content-Type': 'application/json; charset=utf-8'}

Migrating from twitter anywhere api

I m using twitter anywhere api for allowing user to sign in with twitter and get their twitter data to store it my table.Since twitter anywhere api is going to expire soon how can i migrate this functionality to oauth.
my javascript:
<script src="https://platform.twitter.com/anywhere.js?id={{twitterappid}}&v=1"></script>
<script type="text/javascript">
var twt_connected = 0;
var Uuid = '2334443224';
$(function(){
if ($('#twtlogin').length) {
// do something
twttr.anywhere(function(twitter) {
if(twitter.isConnected()){
//alert('Welcome, you are connected');
currentUser = twitter.currentUser;
screenName = currentUser.data('screen_name');
jQuery.ajax({url:"/twitter/Uuid="+Uuid+"/" ,
type: "POST",
data: {user: JSON.stringify(currentUser) },
dataType: "json",
success: function(result) {
}});
document.getElementById("twtlogin").innerHTML = '<img src="/images/icon_tconnected.gif" width="153" height="37" alt="Connected" />';
}
});
}
});
$("#login").click(function(e){
e.preventDefault();
if (twt_connected == 0){
$.post("/twt-click-time/Uuid="+Uuid+"/","clicked",function(data){})
twttr.anywhere(function (T) {
T.bind("authComplete", function (e, user) {
document.getElementById("twtlogin").innerHTML = '<img src="/images/icon_tconnected.gif" width="153" height="37" alt="Connected" />';
twt_connected = 1;
currentUser = T.currentUser;
screenName = currentUser.data('screen_name');
jQuery.ajax({url:"/twitter/Uuid="+Uuid+"/" ,
type: "POST",
data: {user: JSON.stringify(currentUser) },
dataType: "json",
success: function(result) {
}});
});
T.signIn();
});
}
});
</script>
I m using django at my backend.
I'm doing this right now for flask. The easiest option is just to plug-in some server side oauth calls.
It's a reasonably large amount of code so I won't copy and paste the whole thing here, but the github page for simplegeo's oauth2 actually has a "logging into django with twitter" walkthrough that should help out.
After having gone through a few options, I think I like twython best. It's just this to do the first step of the oauth:
from twython import Twython
t = Twython(app_key='key',
app_secret='secret',
callback_url='http://google.com/')
auth_props = t.get_authentication_tokens()
print auth_props

"CSRF token missing or incorrect" while post parameter via AJAX in Django

I try to post parameter like
jQuery.ajax(
{
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': "{content:'xxx'}",
'dataType': 'json',
'success': rateReviewResult
}
);
However, Django return Forbidden 403. CSRF verification failed. Request aborted.
I am using 'django.middleware.csrf.CsrfViewMiddleware' and couldn't find how I can prevent this problem without compromising security.
You can make AJAX post request in two different ways:
To tell your view not to check the csrf token. This can be done by using decorator #csrf_exempt, like this:
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def your_view_name(request):
...
To embed a csrf token in each AJAX request, for jQuery it may be:
$(function () {
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
});
Where the getCookie function retrieves csrf token from cookies. I use the following implementation:
function getCookie(c_name)
{
if (document.cookie.length > 0)
{
c_start = document.cookie.indexOf(c_name + "=");
if (c_start != -1)
{
c_start = c_start + c_name.length + 1;
c_end = document.cookie.indexOf(";", c_start);
if (c_end == -1) c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start,c_end));
}
}
return "";
}
Also, jQuery has a plugin for accessing cookies, something like that:
// set cookie
$.cookie('cookiename', 'cookievalue');
// read cookie
var myCookie = $.cookie('cookiename');
// delete cookie
$.cookie('cookiename', null);
The simplest way I have found is to include the {{csrf_token}} value in the data:
jQuery.ajax(
{
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': {
'content': 'xxx',
'csrfmiddlewaretoken': '{{ csrf_token }}',
},
'dataType': 'json',
'success': rateReviewResult
}
);
It took me a while to understand what to do with the code that Daniel posted. But actually all you have to do is paste it at the beginning of the javascript file.
For me, the best solution so far is:
Create a csrf.js file
Paste the code in the csrf.js file
Reference the code in the template you need it
<script type="text/javascript" src="{{ STATIC_PREFIX }}js/csrf.js"></script>
Notice that STATIC_PREFIX/js/csrf.js points to my file. I am actually loading the STATIC_PREFIX variable with {% get_static_prefix as STATIC_PREFIX %}.
Advanced tip: if you are using templates and have something like base.html where you extend from, then you can just reference the script from there and you don't have to worry anymore in there rest of your files. As far as I understand, this shouldn't represent any security issue either.
Simple and short
$.ajaxSetup({
headers: { "X-CSRFToken": '{{csrf_token}}' }
});
OR
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", '{{csrf_token}}');
}
}
});
docs
For lack of a straight forward answer, you just have to add the header X-CSRFToken to the ajax request which is in the cookie csrftoken. JQuery doesn't do cookies (for some reason) without a plugin so:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
and the minimal code change is:
$.ajax({
headers: { "X-CSRFToken": $.cookie("csrftoken") },
...
});
The fastest solution without any plugins if you are not embedding js into your template is:
Put <script type="text/javascript"> window.CSRF_TOKEN = "{{ csrf_token }}"; </script> before your reference to script.js file in your template, then add csrfmiddlewaretoken into your data dictionary:
$.ajax({
type: 'POST',
url: somepathname + "do_it/",
data: {csrfmiddlewaretoken: window.CSRF_TOKEN},
success: function() {
console.log("Success!");
}
})
If you do embed your js into the template, it's as simple as: data: {csrfmiddlewaretoken: '{{ csrf_token }}'}
I got the same issue yesterday and thought it would help people if there were a simple way to handle it, so I wrote a jQuery plugin for that: jquery.djangocsrf. Instead of adding the CSRF token in every request, it hooks itself on the AjaxSend jQuery event and adds the client cookie in a header.
Here’s how to use it:
1- include it:
<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.cookie.js"></script>
<script src="path/to/jquery.djangocsrf.js"></script>
2- enable it in your code:
$.djangocsrf( "enable" );
Django always add the token in a cookie if your template uses {% csrf_token %}. To ensure it always adds it even if you don’t use the special tag in your template, use the #ensure_csrf_cookie decorator:
from django.views.decorators.csrf import ensure_csrf_cookie
#ensure_csrf_cookie
def my_view(request):
return render(request, 'mytemplate.html')
Note: I’m using Django 1.6.2.
Thank you everyone for all the answers. I am using Django 1.5.1. I'm a little late to the party, but here goes.
I found the link to the Django project to be very useful, but I didn't really want to have to include the extra JavaScript code every time I wanted to make an Ajax call.
I like jerrykan's response as it is very succinct and only adds one line to an otherwise normal Ajax call. In response to the comments below his comment regarding situations when Django template tags are unavailable, how about loading up the csrfmiddlewaretoken from the DOM?
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
type: 'POST',
url: url,
data: { 'csrfmiddlewaretoken': token },
dataType: 'json',
success: function(data) { console.log('Yippee! ' + data); }
});
EDIT March 2016
My approach to this issue over the past few years has changed. I add the code below (from the Django docs) to a main.js file and load it on every page. Once done, you shouldn't need to worry about the CSRF token with ajax again.
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Include x-csrftoken header in request:
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
jQuery.ajax({
type: 'POST',
url: url,
beforeSend : function(jqXHR, settings) {
jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
},
data: data,
dataType: 'json',
});
If, after reading other answers, someone is still struggling please try this:
$.ajax({
type: "POST",
beforeSend: function (request)
{
request.setRequestHeader("X-CSRF-TOKEN", "${_csrf.token}");
},
url: servlet_path,
data : data,
success : function(result) {
console.log("Success!");
}
});
Please not that when doing it this way make sure you don't have the {% csrf_token %} inside the <form></form> tags. Then as explained here add the following code to your javascript
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
// using js fetch
// https://docs.djangoproject.com/en/3.1/ref/csrf/#setting-the-token-on-the-ajax-request
const request = new Request(
/* URL */,
{headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
method: 'POST',
mode: 'same-origin' // Do not send CSRF token to another domain.
}).then(function(response) {
// ...
});
Just want to put it out here that if GET works in your use case, then it wouldn't need the CSRF token. For my use case, using GET was OK.
html
<form action="">
{% csrf_token %}
</form>
JS
<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
const request = new Request(
'url_here',
{headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
method: 'POST',
// mode: 'same-origin' optinal // Do not send CSRF token to another domain.
}).then(function(response) {
console.log(response);
});
</script>
reference link for more detail
As a summary for my mistakes:
Don't forget to set the request content type.
Get the csrf value, either from
The template {{ csrf_token }}
The cookie, use the snippet in django site
NB. The default cookie name is csrftoken, but can be overriden by CSRF_COOKIE_NAME setting.
The DOM, if you can't access the cookie (you set CSRF_USE_SESSIONS or CSRF_COOKIE_HTTPONLY to True)
document.querySelector('[name=csrfmiddlewaretoken]').value;
Set the request header, I'am using XMLHttpRequest
const Http = new XMLHttpRequest();
Http.setRequestHeader("X-CSRFToken", CSRF_VALUE);
Http.setRequestHeader("X_CSRFTOKEN", CSRF_VALUE);
The header name is managed by CSRF_HEADER_NAME setting, which its default is HTTP_X_CSRFTOKEN.
But: "The header name received from the server is normalized by converting all characters to uppercase, replacing any hyphens with underscores, and adding an 'HTTP_' prefix to the name" src.
So, If you set the HTTP_X_CSRFTOKEN header, Django will convert it to HTTP_HTTP_X_CSRFTOKEN which wis incorrect name and will raise CSRF missed error.
Http.setRequestHeader("X-CSRFToken", csrftoken); // This worked
Http.setRequestHeader("X-CSRFTOKEN", csrftoken); // Also this
Http.setRequestHeader("HTTP-X-CSRFToken", csrftoken); // Not working
Http.setRequestHeader("HTTP_X_CSRFTOKEN", csrftoken); // Not Working
Http.setRequestHeader("X_CSRFTOKEN", csrftoken); // Not working !!
Don't use url in ajax that is different than that of the browser 127.0.0.1 & localhost are not the same !!
No need to set data.append("csrfmiddlewaretoken", csrftoken); in the request body, As I know.