Django X-CSRF token cannot be set in javascript fetch - javascript

I am trying to generate a csrf token in javascript and use that with a POST request using fetch.
In my html, I have the following script tag under head to generate the csrf token:
<head>
<script type="text/javascript">
var user = '{{request.user}}'
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;
}
var csrftoken = getCookie('csrftoken');
console.log(csrftoken)
</script>
</head>
Then under body, I have the following script tag where I retrieve the csrftoken variable and pass it to the 'X-CSRFToken' header in fetch():
<body>
<script type="text/javascript">
console.log('Hello World')
console.log(csrftoken)
var updateButtons = document.getElementsByClassName('update-cart')
for(i = 0; i < updateButtons.length; i++){
updateButtons[i].addEventListener('click', function(){
var productId = this.dataset.product
var action = this.dataset.action
console.log('productId: ', productId, 'action: ', action)
console.log('user: ', user)
if(user === 'AnonymousUser'){
console.log('Not logged in.')
}else{
updateUserOrder(productId, action)
}
})
}
function updateUserOrder(productId, action){
console.log('User is authenticated. Sending data...')
console.log(csrftoken)
var url = '/update_item/'
fetch(url, {
method: 'POST',
headers: {
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
body: JSON.stringify({'productId': productId, 'action': action})
})
.then((response) => {
return response.json()
})
.then((data) => {
console.log('data: ', data)
})
}
</script>
</body>
The csrftoken variable is displayed by all the console.log() calls but I still get the following exceptions:
(index):169 POST http://127.0.0.1:8000/update_item/ 500 (Internal Server Error)
updateUserOrder
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
views.py,
def update_item(request):
data = json.loads(request.data)
product_id = data['productId']
action = data['action']
print('action: ', action)
print('product_id: ', product_id)
customer = request.user.customer
product = Product.objects.get(id=product_id)
order, created = Order.objects.get_or_create(customer=customer, complete=False)
orderitem, created = OrderItem.objects.get_or_create(order=order, product=product)
if action == 'add':
orderitem.quantity += 1
elif action == 'remove':
orderitem.quantity -= 1
orderitem.save()
if orderitem.quantity <= 0:
orderitem.delete()
return JsonResponse('Item was added.', safe=False)
I cannot seem to figure out whether it is a syntax error or if I am setting the 'X-CSRFToken' header wrong. Other similar answers did not help.

Solved. It was not an issue with my javascript or the csrftoken variable therein. Rather it was in my server code.
In views.py, I typed data = json.loads(request.data). But it should be data = json.loads(request.body).

Related

Javascript Django like button doesn't update counter

I have created Put request to update like count, but when I press like button count doesn't change unless I refresh page. and like/unlike function works fine.
Can somebody help me resolve this issue?
view.py
Here is how i have done put request.
class PostLikeView(APIView):
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, post_id, slug=None, format=None):
post = Post.objects.get(pk=post_id)
serializer = PostSerializer(post, many=False, )
return JsonResponse(serializer.data, safe=False)
def put(self, request, post_id, slug=None, format=None):
post = Post.objects.get(pk=post_id)
user = self.request.user
# if user.is_authenticated():
if user in post.likes.all():
post.likes.remove(user.id)
else:
post.likes.add(user.id)
serializer = PostSerializer(post, data=request.data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False)
In javascript at like_button.addEventListener i calling function like post where i pass post_id this function works except counter doesnt change unless i refresh page, can I edit so counter update without refreshing if not how to setup automatically to refresh after put request complete?
index.js
function post_list(post) {
const postdiv = document.createElement('div')
postdiv.setAttribute('id','post-div')
const userdiv = document.createElement('div')
userdiv.setAttribute('id', 'username-div')
const bodydiv = document.createElement('div')
bodydiv.setAttribute('id', 'body-div')
const datediv = document.createElement('div')
datediv.setAttribute('id', 'date-div')
const datep = document.createElement('p')
datep.setAttribute('id', 'date-paragraph')
const userp = document.createElement('p')
userp.setAttribute('id', 'username-paragraph')
const bodyp = document.createElement('p')
bodyp.setAttribute('id', 'body-paragraph')
// LIKE
const likesdiv = document.createElement('div')
likesdiv.setAttribute('id', 'likes-div')
let likesp = document.createElement('p')
likesp.setAttribute('id', 'likes-paragraph')
// LIKE BUTTON
let like_button = document.createElement('button')
like_button.setAttribute('id', 'like-button')
const post_id = post.id
let user_id = document.querySelector("#user-id").value;
let likes = post.likes
const postp = document.createElement('p')
postp.innerHTML = post_id
// LIKE COUNTER
let likes_counter = post.likes.length
console.log(likes_counter)
likesp.innerHTML = `Likes: ${likes_counter}`
if (likes.indexOf(parseInt(user_id)) >= 0) {
like_button.innerHTML = 'Unlike'
} else {
like_button.innerHTML = 'Like'
}
like_button.setAttribute('type', 'submit')
like_button.addEventListener('click', () => {
if(like_button.innerText.toLowerCase() === 'like') {
like_button.innerText = 'Unlike';
}
else {
like_button.innerText = 'Like';
}
like_post(post_id, post.likes);
})
datep.innerHTML = post.date
datediv.append(datep)
userp.innerHTML = post.user
userdiv.append(userp)
bodyp.innerHTML = post.post
bodydiv.append(bodyp)
likesdiv.append(likesp, like_button)
postdiv.append(bodydiv, userdiv, likesdiv, datediv, )
document.querySelector('#post-list').append(postdiv)
}
function like_post(post_id) {
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');
let user = document.querySelector('#user-id').value;
fetch(`/posts/${post_id}`, {
method: 'PUT',
headers: {
"X-CSRFToken": csrftoken ,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: user,
id: post_id,
})
})
.then(response => response.json())
.then(result => {
// Print result
console.log(result);
})
}
I've managed to solve my problem. If anyone gets in similar situation to know.
This probable is not the most elegant way to solve this but it works
// LIKE COUNTER
let likes_counter = post.likes.length
likesp.innerHTML = `Likes: ${likes_counter}`
if (document.querySelector("#user-id") != null) {
let user_id = document.querySelector("#user-id").value;
// LIKE BUTTON
let like_button = document.createElement('button')
like_button.setAttribute('id', 'like-button')
if (post.likes.indexOf(parseInt(user_id)) >= 0) {
like_button.innerHTML = 'Unlike'
} else {
like_button.innerHTML = 'Like'
}
like_button.setAttribute('type', 'submit')
like_button.addEventListener('click', () => {
if(like_button.innerText.toLowerCase() === 'like') {
like_button.innerText = 'Unlike';
likes_counter ++
}
else {
like_button.innerText = 'Like';
likes_counter --
}
likesp.innerHTML = `Likes: ${likes_counter}`
like_post(post_id, post.likes);
})
likesdiv.append(like_button)
}

I'm using vanilla js to make a ajax post request to django

I'm trying to make a ajax post request to django this is js snippet
const xhr = new XMLHttpRequest();
console.log(xhr.readyState);
xhr.open('POST', '');
var data = '{% csrf_token %}';
console.log(data);
console.log(typeof(data));
xhr.setRequestHeader('X-CSRF-Token', data);
xhr.onload = function(){
console.log(xhr.readyState);
console.log(xhr.status);
if(xhr.status == 200){
console.log(JSON.parse(xhr.responseText));
}else{
console.log("Something went wrong!!");
}
}
xhr.send({'userId' : userId})
}
This is my error log:
I've been getting a 403 forbidden error can anybody help me out?
This function should get you the csrf-token
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;
}
then:
const csrftoken = getCookie('csrftoken');
to get the csrf-token.
What also might be worth looking at is changing X-CSRF-Token
xhr.setRequestHeader('X-CSRF-Token', data);
to X-CSRFToken
xhr.setRequestHeader('X-CSRFToken', data);
hope this helps
The {% csrf_token %} in the templates page translates to:
<input type="hidden" name="csrfmiddlewaretoken" value="WRWu3DwbdHDl1keRwSqUNrvcwZXqhCzkInEGVftyuwWG0v5kBBzeGrZ34wKpjFB5">
We need to get the CSRF token , i.e., the value of this element:
x = document.getElementsByName("csrfmiddlewaretoken")[0].value;
Then, we need to pass this value to the setRequestHeader method of the JSON request, with "X-CSRFToken" as the first argument:
function requestJSON() {
x = document.getElementsByName("csrfmiddlewaretoken")[0].value;
jsonRequest = new XMLHttpRequest();
jsonRequest.overrideMimeType("application/json");
jsonRequest.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200 ) {
var j = JSON.parse(this.responseText);
// do whatever with the JSON data
}
else {console.log(this.status);}
};
jsonRequest.open("POST","url/");
jsonRequest.setRequestHeader("content-type","application/x-www-form-urlencoded");
jsonRequest.setRequestHeader("X-CSRFToken",x);
jsonRequest.send();
}

Django: problem with format when using ajax query (string/Json)

I try to send data with ajax but the format is a string and I need JSON (or formated data)
Data to be sent are displayed in an HTML table.
I loop in all my rows to collect all data to be send using ajax.
But I have an error when I try to make a JSON object when using JSON.Parse(new_parameters).
If use new_parameters in my ajax query, I get False in my ajax view...
If I "stringify" new_parameters to use it in my ajax query, I get data in my ajax view but in string format...
That's mean the way I construct new_parameters is not a good way...
var parameters = {};
var current_parameters = [];
var new_parameters = [];
// Collect data from html data when user click on "Modify settings" button
$(document).on('click', '#modifier', function(event)
{
event.preventDefault();
$('#table_parametrage tr').each(function() {
var parameter = {};
$(this).find('td div').each (function() {
parameter[$(this).attr("col_name")] = $(this).eq(0).html();
});
new_parameters.push(parameter);
});
new_parameters.shift();
// requête ajax > start
// parameters = JSON.parse(new_parameters, null, 2);
console.log(new_parameters);
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 = 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;
}
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: $(this).data("ajax-url"),
data: {
csrfmiddlewaretoken: csrftoken,
'data' : new_parameters,
},
dataType: 'json',
success: function (data) {
// alert(data);
},
error : function(resultat, statut, erreur){
//
}
});
// requête ajax > end
// Remise à zéro de la liste
new_parameters = [];
parameters = {};
});
for those interested, even if I am not ure it is the best code, I resolve my problem like this:
JS:
...
parameters = JSON.stringify(new_parameters, null, 2);
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 = 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;
}
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: $('#modifier').data("ajax-url"),
data: {
csrfmiddlewaretoken: csrftoken,
'data' : parameters,
},
dataType: 'json',
success: function (data) {
// alert(data);
},
error : function(resultat, statut, erreur){
//
}
});
# requete ajax
def ajax(request):
if request.method == "POST":
data = request.POST.get('data',False)
# https://www.programiz.com/python-programming/json
data_dict = json.loads(data)
print(data_dict)
print(data_dict[0]['ran_st1'])
else:
datas = ''
print('echec')
return render(request, 'randomization_settings/ajax.html', {})

ASP.NET REST POST - JavaScript (jQuery) Send Body in POST

I have a REST call that is working fine when I call it from a C# app, but I can't make my JavaScript page send the content in the body of the POST. This is the REST controller. Note the JavaScript below works fine if I remove the "FromBody" attribute from the call.
[Route("api/[controller]")]
public class AuthenticateController : Controller
{
[HttpPost]
public ActionResult Post([FromBody] CredentialsModel credentialsModel)
{
var authenticationModel = new AuthenticationModel { IsSuccess = false };
if (credentialsModel != null && !string.IsNullOrEmpty(credentialsModel.Username) && !string.IsNullOrEmpty(credentialsModel.Password))
{
authenticationModel = SecurityBusinessLayer.IsValidUser(credentialsModel.Username, credentialsModel.Password);
}
var json = JsonConvert.SerializeObject(authenticationModel, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ReferenceLoopHandling = ReferenceLoopHandling.Serialize });
return Content(json);
}
}
This is the JavaScript using JQuery:
function authenticate(username, password)
{
//Get the authenticate api url
var uriHref = window.location.href;
var lastIndexOfSlash = uriHref.lastIndexOf('/');
var apiPath = uriHref.substring(0, lastIndexOfSlash) + "/api";
var encodedUri = encodeURI(apiPath + "/authenticate/");
var credentials = {};
credentials["Username"] = username;
credentials["Password"] = password;
//Post the username and password to the server
$.post(encodedUri, credentials, function (data)
{
//Parse the returned data (should match Adapt.Data.Generic.AuthenticationModel)
var response = JSON.parse(data);
if (response.IsSuccess)
{
//Ensure the token will expire
var expiryDate = new Date();
expiryDate = new Date(expiryDate.setTime(expiryDate.getTime() + 86400000));
//Set the auth token cookie
var cookieString = "authToken=" + response.Authtoken + "; expires=" + expiryDate.toUTCString() + ";path=/";
document.cookie = cookieString;
//Goto the xivic app page
window.location = "Index.html";
}
else
{
//Failed to log in, show error message
$("#badLoginMessage").css("visibility", "visible");
}
});
}
When you remove [FromBody, you have to post Json object instead of array]
$.ajax({
url: encodedUri,
type: 'POST',
data: {
Username: jsonString,Password:password
},
success: function (data) {
if (data.Success == true) {
}
else
{
}
},
error: function () {
},
complete: function () {
}
});
This is the working code based on #LeTungAnh, and #ibubi's code. I can't help but think that $post would still be a better method though. The reason $post was not working was that it was not sending a content type of application/json which is what ASP.NET Core requires.
function authenticate(username, password) {
//Get the authenticate api url
var uriHref = window.location.href;
var lastIndexOfSlash = uriHref.lastIndexOf('/');
var apiPath = uriHref.substring(0, lastIndexOfSlash) + "/api";
var encodedUri = encodeURI(apiPath + "/authenticate/");
var credentials = {};
credentials["Username"] = username;
credentials["Password"] = password;
var credentialsJson = JSON.stringify(credentials);
$.ajax({
url: encodedUri,
type: 'POST',
data: credentialsJson,
contentType: 'application/json',
success: function (responseJson) {
var authenticationObject = JSON.parse(responseJson)
if (authenticationObject.IsSuccess == true) {
//Ensure the token will expire
var expiryDate = new Date();
expiryDate = new Date(expiryDate.setTime(expiryDate.getTime() + 86400000));
//Set the auth token cookie
var cookieString = "authToken=" + authenticationObject.Authtoken + "; expires=" + expiryDate.toUTCString() + ";path=/";
document.cookie = cookieString;
//Goto the xivic app page
window.location = "Index.html";
}
else {
//Failed to log in, show error message
$("#badLoginMessage").css("visibility", "visible");
}
},
error: function () {
//Failed to log in, show error message
$("#badLoginMessage").css("visibility", "visible");
},
complete: function () {
}
});
}

Phonegap:Login Through LinkedIn Error While Getting Access Token

I'm trying to implement Login through LinkedIn using the following link Login through LinkedIn
.
Below is my code`
var oauth_info = {};
var consumer_key = "";
var shared_secret = "";
var oauth = OAuthSimple(consumer_key, shared_secret);
function parse_response(response) {
response.replace(new RegExp("([^?=&]+)(=([^&]*))?", "g"), function($0, $1, $2, $3) { oauth_info[$1] = $3; });
console.log("oauth_token1="+oauth_info.oauth_token);
}
function linkedInLogin()
{
var url = oauth.sign({action: "GET", path: "https://api.linkedin.com/uas/oauth/requestToken", parameters: {oauth_callback: "http://www.example.com/"}}).signed_url;
console.log("url==="+url);
$.ajax(
{
url:url,
data: {},
success: function(data){
console.log("inside success");
console.log("response==="+data);
parse_response(data);
console.log("oauth_token2="+oauth_info.oauth_token);
var params = data;
params = params.split('&');
for (var i = 0; i < params.length; i++) {
var y = params[i].split('=');
if(y[0] === 'oauth_token') {
localStorage.oauth_token = y[1];
console.log("oauth_token=="+localStorage.oauth_token);
}
if(y[0]==='oauth_token_secret')
{
localStorage.oauth_token_secret=y[1];
console.log("oauth_token_secret=="+localStorage.oauth_token_secret);
}
}
step2();
},
error: function(error) {
console.log("error");
client_browser.close();
},
dataType: 'text',
type: 'GET'
});
}
function step2()
{
var authoriseurl='https://www.linkedin.com/uas/oauth/authenticate?oauth_token='+oauth_info.oauth_token+'';
window.plugins.childBrowser.showWebPage(authoriseurl);
window.plugins.childBrowser.onLocationChange = function(loc){
console.log("on loc changed");
linkedInChanged(loc);
};
}
function linkedInChanged(loc)
{
console.log("inside loc changed");
if (loc.indexOf("http://www.example.com/") > -1) {
window.plugins.childBrowser.close();
console.log("oauth_token3="+oauth_info.oauth_token);
var index, verifier = '';
var params = loc.substr(loc.indexOf('?') + 1);
params = params.split('&');
for (var i = 0; i < params.length; i++) {
var y = params[i].split('=');
if(y[0] === 'oauth_verifier') {
verifier = y[1];
console.log("verifier===="+verifier);
}
}
var acces_url= access_token_url(verifier);
oauth.reset();
console.log("oauth_token4="+oauth_info.oauth_token);
//console.log("oauth_info"+oauth_info[0][0]+"===="+oauth_info[0][1]);
//var url = oauth.sign({action: "GET", path: "https://api.linkedin.com/uas/oauth/accessToken", parameters: {oauth_verifier: verifier}, signatures: oauth_info}).signed_url;
console.log("access _url="+acces_url);
$.ajax(
{
url:acces_url,
data: {},
success: function(data){
console.log("inside access token success");
console.log("response==="+data);
var params = data;
params = params.split('&');
for (var i = 0; i < params.length; i++) {
var y = params[i].split('=');
if(y[0] === 'oauth_token') {
localStorage.linkedIn_access_Token = y[1];
console.log("linkedIn_access_Token=="+localStorage.linkedIn_access_Token);
}
if(y[0]==='oauth_token_secret')
{
localStorage.linkedIn_access_secret=y[1];
console.log("linkedIn_access_secret=="+localStorage.linkedIn_access_secret);
}
}
},
error: function(error){
console.log("error=="+error.responseText);
},
dataType: 'text',
type: 'GET'
});
}
}
function get_url_vars_from_string(url) {
var vars = [], hash;
var hashes = url.slice(url.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function access_token_url(pin) {
oauth.reset();
//alert(oauth_info.oauth_token);
var url = oauth.sign({action: "GET", path: "https://api.linkedin.com/uas/oauth/accessToken", parameters: {oauth_verifier: pin}, signatures: oauth_info}).signed_url;
// alert("url="+url);
return url;
}
`
On click of a button the linkedInLogin method is called.
I'm not able to get the access token from this code.The ajax call for access token results in Error oauth_problem=token_rejected
Please help
I had the same problem, and found out where the issue comes from.
So, I've come to the request for the accessToken, and have to generate the signature. When I call OAuth.completeRequest() - this is where the signature gets generated - I pass two parameters, and the second one is an object that contains four things (the first two are application settings and next two are from my first request, for the request token):
The api key.
The api secret.
The request token.
The request token secret.
The fourth one was missing on my end. That was the problem.
Also - I'm using this OAuth library - http://oauth.googlecode.com/svn/code/javascript/oauth.js, so the methods/functions on your end could have completely different name. But you've got the idea.
Hope this helps ;)

Categories

Resources