# Secure authentication using JavaScript module pattern and an AJAXified modal window

This code is not live, but for brevity I'll write as though it is.

When a user clicks any element with the class name js-modalOpen, for example:

<span class="js-modalOpen" data-modal="signup">Sign up</span>


A modal appears. The contents of that modal's dialog are determined by data-modal. All modal contents live as snippets in my framework's static/html/ directory. My first concern is that I'm calling the methods and then binding their behavior to the target elements. Somehow it makes sense to me, but I've rarely seen it in production. Thus:

Modal.modalOpenListener();


Would call

var Modal = (function ($, SCRIPT_ROOT, CSRF_TOKEN) { methods = {}; methods.modalOpenListener = function() {$(".js-modalOpen").on("click", function() {
var snippetType = $(this).attr("data-modal"); var snippet = SCRIPT_ROOT + "/static/html/" + snippetType + "_modal_snippet.html";$(".modal").toggle();
$(".modal").addClass("visible"); document.body.style.overflow = "hidden"; dialogContentsLoad(snippetType, snippet); }); } return methods; })(jQuery, SCRIPT_ROOT, CSRF_TOKEN);  The general structure of the code follows this pattern within the module. I'm concerned chiefly about • Security (I'm bad at this) • Modularity I'll paste the whole code base I currently have for the sake of anyone brave enough to wade through it. var Modal = (function ($, SCRIPT_ROOT, CSRF_TOKEN) {

methods = {};

// TODO:
// 1. Write a function that gathers the values of the input
// so that if the user accidentally closes the modal, the
// values remain when it's reopened.
// 2. Write a function the stops the ability to tab into
// the main web page when the modal is open
// 3. If a given form field IS NOT ".js-required" and IS empty,
// don't serialize that part, so it gets ignored in error
// checking

var dialogContentsLoad = function(snippetType, snippet) {
$(".dialogContents").load(snippet, function() { // If there's a form in the dialog, do this (".length" because // jQuery will simply return an empty array if there's not matching // element) if ($(".dialog").find("form").length) {
var formType = snippetType;
var form     = formType + "Form";
// All modal fields will have a tabindex of "0"
$("input").first().attr("tabindex", "0").focus();$("input[name='_csrf_token']").val(CSRF_TOKEN);
// This should probably be taken out of this function...right?
$("input").on("focus", function() {$(this).css("background-color", "#2b2b2b")
});
$("input").on("blur", function() {$(this).css("background-color", "#4b4b4b")
});
formSubmitListener(form, formType, CSRF_TOKEN);
}
});
}

var formSubmitListener = function(form, formType, CSRF_TOKEN) {
var destinationURL = SCRIPT_ROOT + "/" + formType + "_action";
$("#" + form).bind("submit", function(e) { e.preventDefault();$.ajax({
type: "POST",
data: $("#" + form).serialize(), url: destinationURL, success: function(resp) { if (resp != "0") { errors =$.parseJSON(resp);
console.log(errors['emptyFields']);
$("." + form + "Errors").empty(); if (!$.isEmptyObject(errors.emptyFields)) {
$("." + form + "Errors").append("Please fill out all required fields.") for (error in errors.emptyFields) {$("input[name='" + errors.emptyFields[error] + "Signup']").css("background-color", "#f22166");
}
}
delete errors.emptyFields;
console.log(errors);
for (error in errors) {
$("." + form + "Errors").append(errors[error]); } } else { location.reload(false); } } }); }); } methods.modalOpenListener = function() {$(".js-modalOpen").on("click", function() {
var snippetType = $(this).attr("data-modal"); var snippet = SCRIPT_ROOT + "/static/html/" + snippetType + "_modal_snippet.html";$(".modal").toggle();
$(".modal").addClass("visible"); document.body.style.overflow = "hidden"; dialogContentsLoad(snippetType, snippet); }); } methods.modalCloseListener = function() {$(document).on("keyup", function(e) {
if (e.keyCode == 27 && $(".modal").hasClass("visible")) {$(".modal").toggle();
$(".modal").removeClass("visible"); document.body.style.overflow = "visible"; } });$(".js-modalClose").on("click", function(e) {
if (e.target == this) {
$(".modal").toggle();$(".modal").removeClass("visible");
document.body.style.overflow = "visible";
}
});
}

return methods;

})(jQuery, SCRIPT_ROOT, CSRF_TOKEN);


I appreciate any input I can get on this.

From a once over:

• // This should probably be taken out of this function...right? <- Yes, this should be in css
• var formSubmitListener = function(form, formType, CSRF_TOKEN) <- Asking for CSRF_TOKEN is superfluous, you already have access to it via
var Modal = (function ($, SCRIPT_ROOT, CSRF_TOKEN) { • console.log should be avoided in production code • Whereas on the whole your code seems re-usable, this particular seems really specific and not re-usable: $("input[name='" + errors.emptyFields[error] +"Signup']").css("background-color", "#f22166");
• You copy pasted this a number of times, use a helper function:

$(".modal").toggle();$(".modal").addClass("visible");
document.body.style.overflow = "hidden";

• I would place the // TODO: above the var Modal
• location.reload(false); <- This is antithetical to AJAX, why do AJAX and then refresh the whole page anyway on success? It does not make sense to me.
• I think it is okay to be very specific in building the location of your script URL:
var snippet = SCRIPT_ROOT + "/static/html/" + snippetType + "_modal_snippet.html"; but you have to be cognizant that you are coupling front and back end really tightly here.