I have an ExtJS 4.1 app with a Ruby on Rails 3.2 back-end using Devise (with Timeoutable enabled) for authentication, session management.
This issue occurs on the server, where the app is served up over SSL only. Nginx redirects any non-secure requests to the https url.
The issue is that when the Devise session has timed out, in my case after 15 minutes, any AJAX request gets sent/redirected to http://myapp.com/controller?params, instead of https://myapp.com/controller?params, as it would normally do.
I have client-side code, that in a non-SSL set up works fine at catching the potential session expired issue, and redirects to the Log In page with a message that the session has timed out. It’s kind of a hack based on the fact that when a request is made after the session has timed out, an “invalid JSON string” error message is returned. The error contains the HTML of the Log In page, because the response that’s supposed to be json when the user is logged in becomes the Log In page to which the app is supposed to be redirected to on session timeout. This block of code is within my Ext.application‘s launch method:
launch: function () {
Ext.Error.handle = function (err) {
$.post('/logs', {message:err.msg});
if (err.msg.indexOf("invalid JSON String") != -1 && err.msg.indexOf("<!DOCTYPE html>") != -1) {
if (err.msg.indexOf("MyApp_Login") != -1)
document.location.href = "/logout?timeout=1";
else
document.location.href = "/logout?error=1";
} else {
gritter(3, "ERROR:", "A client-side error has occurred. If this issue persists, please contact your system administrator.");
if (Ext.isWebKit) console.log(err);
}
}
if (user_signed_in == true) {
Ext.require('MyDesktop.App');
Ext.require('Ext.tab.*');
_myDesktopApp = Ext.create('MyDesktop.App');
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
}
}
So as I said above, over non-secure socket the app detects a controller request (or more precisely response) that indicates the session is timed out, and takes appropriate action. But on my server, over SSL, for some reason the controller calls end up being over http and not https once the session has expired. Causing errors like this in Chrome:
The page at https://server.myapp.com/ displayed insecure content from http://server.app.com/campaign_components_contacts.json?authenticity_token=1vokGHUpsi5w3b3P8mrfUpEGx19hrHJpsCzPayofM7c%3D&campaign_id=2&component_id=2&contact_id=1536&format=json
Could this be a feature of ExtJS, where it tries a non-secure call when a problem is detected over SSL? Or some feature of Rails? I’m sure it’s neither, but just throwing out some things that have come up in my head.
EDIT:
I have been able to test the scenario out locally, in dev environment, by using thin with the –ssl switch. Once the server is started up, I browse to
https://localhost:3000
with no problems. Once the Devise session expires, any json request triggers the redirect to login, as expected and works over http.
So the issue described in this question appears only on my server, and probably has to do with the way my NGINX config is set up.
I will also precompile the app locally and run with prod environment option, just to make sure it’s nothing to do with the difference between dev and prod.
Wow, turned out to have nothing to do with the Devise session timeout, Rails or ExtJS.
Finally got it resolved by tweaking NGINX config, which was supposedly correct for the version used, according to documentation, but turned out to be causing this issue.
Current ssl server bit:
Before I had:
The difference is splitting up
into: