Rails Devise timeoutable does not reload page even if AJAX request fails - ruby-on-rails-4

I am using Devise gem for authentication. I have used timeoutable feature of devise to redirect to login page if no user activity seen for specified time. The issue is mainly when ajax request is sent and session timed out, the UI becomes nonresponsive. Below is my configuration:
In User model:
devise :timeoutable
def timeout_in
if self.role.name == "Admin"
30.minutes
end
end
This does the timeout(session expires after 30 mins if no user activity is seen). But it does not autorefresh page to show the signin page. I have even tried to use javascript that does the regular check if session has expired or not and if expired, just reload the page mainly for ajax request in order to avoid unresponsive UI. But this does not work either. Any help would be appreciated..

Whenever AJAX request encounters a 401 i.e., Unauthorized token error, refresh/ reload the page :
var jqXHR = $.ajax({
url: "/validate_barcode",
type: "GET",
dataType: "json",
data: {barcode: barcode},
}).done(function (data,status,jqXHR) {
console.log("Success");
}).fail(function (jqXHR,status,err) {
// alert("Promise error callback.");
if(jqXHR.status == 401){
location.reload();
}
})
This worked and reloaded the page to show login screen if session timedout and UI became non responsive.

Related

Uncaught DOMException: Blocked a frame with origin "http://localhost:8000" from accessing a cross-origin frame

I am currently building a website with Django and Javascript. I am working on the ajax calls that would the data needed for populate my homepage. However, I keep getting this cross-origin error. I have tried setting the document domain, enabling CROS headers and passing CSRF tockens. All attempts have been unsuccessful. Please take a look at my javascript code above.
if (window.scrollY > news_elementTarget.offsetTop) {
if (!news_fetched) {
$.ajax({
url: '/ajax/home',
type: 'get',
data: {
button_test: $(this).text(),
section: 'news',
CSRF: csrftoken,
},
success: function (response) {
console.log('success')
create_section_1(response.id, response.sections)
news_fetched = true
}
})
}
}
I'm trying to make an ajax call to the backend when the window scrolls to a certain div. The get request is never even sent to the backend. I really confused because I thought my domains are the same which wouldn't cause a Cross-origin error.

Send X-CSRF Token to a Django server using XHTTP Request or jQuery Ajax

I've been trying to make a POST to my Django application via XHTTP Request and jQuery with no correct result at all.
The fact is that the Django app is on one of my subdomains, and the web app is in another, not being part of the Django app, just only a separated app.
I've been reading the docs, but none of this works.
All of my subdomains are in the ALLOWED HOSTS list and in the CORS ORIGIN WHITELIST, and the petition works correctly with GET, but POST returns me a Forbidden 403 error telling CSRF Cookie not found.
This is the code of my petition.
var petition = new XMLHttpRequest();
petition.open('POST','http://localhost:8000/login/',true);
petition.setRequestHeader("X-CSRFToken",sessionStorage["csrf_token"]);
petition.send()
I already have stored the CSRF cookie in the session storage with this function.
function storeCSRFToken(){
var token;
$.ajax({
url : 'http://localhost:8000/token',
type: "GET",
dataType : "json",
success: function( data ){
token = data.csrf_token;
sessionStorage['csrf_token'] = token;
}
});
}
Any clue of what is going wrong?

chrome extension getting session data from website

in my django project, i have a url that has login_required set, because i need the request.user variable in it to process some data,
i also created a simple chrome extension where i'm going to have to send requests to that django project url.
i do not want to use the username and password in the extension to login and send the request
i want to:
redirect the user when the extension is installed to the my website
they will login,
the extension will know that the user has logged in and it will get (and save) a key that i could maybe inject in the page after login is successful
the key can be used as a query parameter in the request in order to identify the user without any username and password
i'm sorry if this seems as a stupid question, but i'm very confused on how to do this
PS: i have already a system in place where the user can use a key in order to make requests without logging in,
i just need a way to open a tab when the extension is installed, and login then get the key (which is injected in the page after login), and save it to use it in the extension later.
When the extension is opened for the first time, I'm showing the user a login page. The login page sends the username & password to an API where they are authenticated. If the information is correct, the required user info is returned (mainly the API key). The information is then saved to local storage.
var username = document.querySelector('[name="username"]');
var password = document.querySelector('[name="password"]');
$.ajax({
URL : 'https://example.com/api/extension-auth/',
type: 'POST',
crossDomain: true,
data: JSON.stringify({
'username': username.value.trim(),
'password': password.value.trim(),
}),
success: res => {
if (res.api_key) {
browser.storage.sync.set({ 'user_data': {'api_key': api_key} }, () => {
// show extension main logged in page
});
}
else {
// show invalid login information alert
}
},
error: function (err) {
// show server error aler
},
});
Everytime the extension is opened the local storage is checked
browser.storage.sync.get('user_data', data => {
if (data.user_data) {
if (valid_api_key(data.user_data.api_key)) {
// show extension main logged in page
}
else {
// show login page
}
}
else {
// show login page
}
});
the valid_api_key function makes a random call to the API to check if there is not an authentication error.
Then, I use the saved API key from local storage to do API requests.

Django function working in Chrome,Opera and Microsoft Edge but not in FireFox

I have written a delete function,when user click logout button it triggers ajax call which calls delete function and destroys session.I am saving my session in file. But problem is my code is working fine in different browsers otherthan Firefox, in firefox when i clcik logout button it performs the task but terminate the performance abnormally which out redirecting back to the home page. Logout operation doesnt take me back to the localhost:8000,instead of that it stays in localhost:8000/logout. But same code working fine on other browsers and redirecting back to home page successfully!
def logout(request):
if request.session.has_key:
request.session.delete()
else:
pass
return JsonResponse({'logout':True,'redirect_url': reverse('sanjh:home')})
<script>
$(document).ready(function(){
$('#logout-anchor').click(function(event){
console.log('hi-you are logged out')
$.ajax({
method: 'GET',
url: '/logout',
success: function(res) {
console.log(res);
window.location = res.redirect_url;
}
})
})
})
</script>]

csrf_token of Django into Vuejs when seperate them

I am using ajax request to send POST but it got response 403 because of csrf_token. I divide the frontend just using Vuejs and backend using Django to just reponse API only so I can't use Django template to render {% csrf_token %} or having csrftoken in session to use getcookie('csrftoken') like in Django's doc recommend. Is there anybody face this problem like me and got some solutions ? So thank you if you can help me this.
You can set the CSRF token in the header of your AJAX request. E.g., if you use jquery and jquery.cookie library, you can easily retrieve the Django-set csrftoken cookie like so:
$.ajax({
url : 'YOUR_URL_HERE',
headers: {'X-CSRFToken': $.cookie('csrftoken')},
type: 'POST',
dataType: 'json',
data: {},
success: function() {
},
error: function(xhr, errMsg, err) {
},
});
Django documentation also includes a section on this: https://docs.djangoproject.com/en/1.11/ref/csrf/#ajax
Please note that this solution may depend on your specific Django settings. The Django documentation link above details everything pretty clearly.
EDIT:
Given that even your initial page request is not served by Django, here is how you can accomplish what you're looking for...
1.) Create a view in your Django app that manually generates and returns a CSRF token (using django.middleware.csrf.get_token):
def get_csrf_token(request):
token = django.middleware.csrf.get_token(request)
return JsonResponse({'token': token})
2.) You would also need to add an appropriate entry in your Django URLs file:
url(r'^get-token/$', get_csrf_token)
3.) Then your Vue.js app can fetch the CSRF token using this endpoint. This doesn't need to be a user-initiated event; for example, you can configure your front-end app to fetch it on the $(document).ready() event. Then, using your preferred AJAX library (I am using jQuery in my example):
$.ajax({
url: '/get-token/',
type: 'GET',
dataType: 'json',
success: function(data) {
$.cookie('csrftoken', data.token); // set the csrftoken cookie
}
});
4.) Now your csrftoken cookie is set and should be usable for subsequent POST requests.
$.ajax({
url : 'YOUR_URL_HERE',
headers: {'X-CSRFToken': $.cookie('csrftoken')},
type: 'POST',
dataType: 'json',
data: {},
success: function() {
},
error: function(xhr, errMsg, err) {
},
});
I have used jQuery for AJAX functionality and the jQuery.cookie library for getting and setting cookies, but of course you can use whichever library you would prefer for these functions.
According to the Django documentation you can simply use the ensure_csrf_cookie decorator on a view and that will send the cookie with the token with the response.
This is going to be wildly unpopular, but I've found it to be a relatively simple, secure and unobtrusive way to separate the front/backend.
In your VueJS app, you've probably got a login redirect when the user tries to access a page and are unauthenticated.
So instead of sending it to a vue router page, redirect it to /account/login/ (or some django app route - put an exception in cloudfront, or nginx proxy for /account/login/ to proxy pass to django) - then in the login.html template, just use a javascript window.location.href to your vueJS login page /login
The csrf_token will be set as a HttpOnly, secure cookie (which is what you want), and the disruption to the user is so minimal as to not even justify worrying about.