This document summarizes the technical journey of building a dynamic login popup overlay within a Django project that spans multiple subdomains. The project integrates traditional Django authentication, frontend overlays, and session sharing — all while dealing with CSRF constraints, static page compatibility, and legacy framework limitations (Django 1.x with Python 2.7).
JavaScript-Based Login Popup Overlay
The primary requirement was a JavaScript file that could be injected via <script src="...">
on any page — including static HTML files — to display a login popup to unauthenticated users. This popup needed to:
- Render dynamically using Django templates
- Check login status via
request.user.is_authenticated
- Display a styled modal resembling Facebook's login box
- Support CSRF token handling inside a
<form>
- Be closable by the user
This was accomplished using a Django view that returns JavaScript via render_to_string()
. Inside the JS, we inserted a full HTML overlay using overlay.innerHTML
with a form, styled buttons, and an embedded CSRF token.
Fixing CSRF Verification Failures
During implementation, attempts to post login forms from static or cross-origin pages caused CSRF errors, especially:
403 Forbidden: CSRF verification failed — Referer mismatch
To resolve this, we updated the settings.py
file:
CSRF_TRUSTED_ORIGINS = [
'https://be.propenda.com',
'https://heylenvastgoed.propenda.be'
]
SESSION_COOKIE_DOMAIN = '.propenda.be'
CSRF_COOKIE_DOMAIN = '.propenda.be'
However, we discovered the real issue: be.propenda.com
and heylenvastgoed.propenda.be
are on entirely different top-level domains (.com
vs .be
), meaning cookies and sessions are not shared.
Temporary Fix: Disabling CSRF for the Login View
To move forward in a non-production environment, we temporarily exempted the login view from CSRF protection using:
from django.views.decorators.csrf import csrf_exempt
url(r'^accounts/login/$', csrf_exempt(LoginView.as_view()), name='account_login')
AMP Compatibility Issue
At one point, an AMP-enabled page caused a failure on login submission due to AMP's strict enforcement of action-xhr
for method="POST"
forms. AMP was later removed from the page entirely to simplify interaction with Django’s CSRF middleware and restore full HTML compatibility.
Using Iframes for Cross-Origin Login
A major design decision was to embed the login form inside an iframe hosted on the main login domain. Upon successful login, the iframe posts a message to its parent window:
// Inside iframe:
window.parent.postMessage("login-success", "*");
// Parent window:
window.addEventListener("message", function(e) {
if (e.data === "login-success") {
document.getElementById("popup-overlay").remove();
location.reload();
}
});
This solution sidestepped cookie and session issues caused by domain mismatch between .com
and .be
.
Alternative Login Technologies Considered
We discussed Shibboleth as a potential federated authentication provider but decided it was unnecessary for this use case. Instead, we focused on pure Django setups:
- Shared database between Django instances
- Shared
SECRET_KEY
to maintain session consistency - Matching
AUTH_USER_MODEL
across subdomains
Final Setup: Two Django Projects, One Auth
The final working architecture includes:
- Two Django projects: one at
be.propenda.com
, one atheylenvastgoed.propenda.be
- Shared PostgreSQL database for user data
- Shared
SECRET_KEY
and session settings - A popup overlay that conditionally appears using server-rendered JavaScript
- A login iframe with
postMessage()
support for seamless cross-page authentication
Next Steps
This implementation is temporary and will eventually be rebuilt. Future improvements may include using OpenID Connect or central authentication via a dedicated subdomain like auth.propenda.be
. For now, the system successfully allows login detection and popup control across subdomains, even on static HTML pages.
Comments
Post a Comment