Generating CSRF token for Backbone from Django - django

I've been developing a backbone layer on top of Django and using Django to create the API and having backbone models calling django api to fill in the models. I'm trying to create a login for users using the default django models for users. Since I'm not rendering the pages through django but instead through router in backbone. I can't generate csrf token through django's template language {{ csrf_token }} and thus I can't post any forms.
One way I thought to work around this is to generate the token by having the backbone view fetch from the api endpoint in initialize and have the endpoint generate the token through
token = csrf._get_new_csrf_key()
and then passing it to backbone frontend through json then following the django documentation
var csrftoken = "<%=obj.csrftoken%>";
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", csrftoken);
}
}
});
This didn't work since I still get Forbidden (403) CSRF verification failed. Request aborted.
Any help would be appreciated. Thanks

The simplest workaround is to read the csrftoken cookie and pass it to django via as X-CSRFToken header. This section in the Django docs should give you the correct example:

Related

Why is my DRF view accepting post requests without a csrf token in the headers?

I've just started using Django Rest Framework, and I'm slightly confused about the usage of CSRF tokens in requests. For example, using a standard Django view with the below request would require a CSRF token:
fetch("http://127.0.0.1:8000/api/add_item/", {
method: "POST",
headers: {
"Content-Type": "application/json"
// "X-CSRFToken": Cookies.get("csrftoken")
},
body: JSON.stringify({ content: value })
})
But doesn't seem to with the below DRF implementation:
#api_view(['POST'])
def add_item(request):
serializer = ToDoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
Is there a reason for this?
DRF does not use the same underlying authentication as Django forms by default. No CSRF tokens are expected.
You must configure Authentication for DRF separately. For example, enabling session-based authentication you can set default auth classes in your settings.py file:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
# ... add other auth methods here
]
}
Also note from the docs regarding CSRF tokens with session auth in DRF:
CSRF validation in REST framework works slightly differently from standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.

How can I transfer Django session authentication to my Vue frontend?

My app uses Django and rest framework backend, Vue frontend. I would like users to use session authentication and login via Django's allauth, with its email verification and password reset support. On login, users are redirected to a Vue component, and I can put the CSRF token into request headers.
I need to get user object (or user ID) into my Vuex store at this point. Are these my choices, or are there others?
give up using session authentication and use JWT
put some kind of session data or token into localstorage that Vue could then retrieve. (How could I do this?)
somehow get user ID from CSRF token
Any advice appreciated.
Duh. Sending request to view/endpoint for getting the authenticated user using Django's request.user worked like a charm, given that my Vue is also running on same localhost:8000 port as Django
in views.py:
class AuthUserView(APIView):
def get(self, request):
serializer = AuthUserSerializer(request.user)
return Response(serializer.data)
in Vue:
methods: {
getUser() {
fetch('/api/auth_user')
.then(response => response.json())
.then(data => console.log(data));
}
}

Connect users to a Django website with React-Native

I have a Django website running, where users can login, save data, take notes, etc. I want to make a mobile app for this website and I am looking into react-native, as I made my website front end with React-JS.
I want to be able to fetch users data on the website from the app. I saw that React-Native had the fetch function, similar to AJAX calls. The problem is that I need the user to be authenticated for the POST call to return something, as I am reading the request.user value to grab the proper data. I also know that without the proper csrf token, Django won't allow a POST call.
How can I do a fetch with the proper request.user value and pass the csrf security test from the react-native app?
For your mobile application, I would create first of all and API with Django Rest Framework. In authentication, you should use Token Authentication so in each request will have the follow hearder Authorization: Token user_token. With this token you can identidy the user as usual using request.user in your views.
In React-Native, you should use axios to do the request for login( to get the token) and them the user data:
const config = {
headers: {
'X-CSRFToken': Cookies.get('csrftoken'),
'Content-Type': 'application/json'
}
};
axios.get(`${ROOT_URL}api/users/data/`, config_user)
.then(response => {
console.log(response.data) // User Data
});

Django API for login/logout with S3 site is not creating cookies

I'm working with a static webpage hosted on S3 and I'm using a Django as my api for session management.
I have my JS code on S3 POSTing to django when users sign in to my web site but I'm not getting any cookies saved on my browser.
I'm not sure if it's the jQuery $.post that is not accepting cookies or if it's Django that's not allowing the sending of cookies. How would I overcome this?
I currently also have a url endpoint on my django app where I can check if cookies are working but when I hit the url I get the standard message
Please enable cookies and try again.
Although my browser accepts cookies.
I get these urls to work fine when I use a Django rendered page to interact with them.
Any help would be greatly appreciated - thanks
Edit - showing code:
I use Janrain to allow user to login via facebook, twitter, etc..
how Janrain works
user clicks sign in button, uses facebook/wtv to login
Janrain get's user data on their servers and gives you a token which I post to django via this function
janrain.events.onProviderLoginToken.addHandler(function(tokenResponse) {
$.ajax({
type: "POST",
url: post_form_url,
data: formdata + "&token=" + tokenResponse.token,
success: function(res, textStatus, jqXHR) {
//do stuff now that we are logged in ...
console.log(jqXHR.getResponseHeader('Set-Cookie')); //returns null
//$('#redirect').submit();
},
});
In Django
def login_via_janrain(request):
if request.method == "POST":
janrain_token = request.POST.get('token')
// communicate w/janrain api to get info from this token (i.e. who just logged in via this token)
#create (or pull) user based on data returned from janrain api and do a Django login
auth.login(request, user)
#return success msg to $.post (session cookies should be automatically included in the response)
return HttpResponse("success")
Using S3
I currently have a static site hosted on S3. I tested these urls using django rendered views but ultimately I want the S3 site to render the views and just use django as an api endpoint.
I can currently login from the S3 site but after a successful login I have no cookies to show for it... I think django isn't sending back cookies...

Cookies not working with an AJAX call from jQuery to Django

I have a Django site using a 5-star rating system for voting (I use django-ratings) and I would like to store the votings of the users with AJAX calls.
On the client side I have a JavaScript function sending a GET request to a URL:
$.ajax({
url: url,
success: function(data) {
alert('Load was performed.');
}
});
On the server side I have code setting the cookie:
def vote(request, slug, rating):
# Some irrelevant code...
response = HttpResponse('Vote changed.')
response.set_cookie('vote', 123456)
return response
The problem is that the cookie is never set in the browser.
What I am doing wrong?
Thanks!
Are sure that your problem is about Cross-site request forgery protection? most ajax requests rejected django by that. Don't you have any error messages?