diff --git a/reviewboard/static/rb/js/models/commentEditorModel.js b/reviewboard/static/rb/js/models/commentEditorModel.js
index 61b8e7272f7562fc47676841dbce361ffb0c2dc2..c0496c695becc11b121f1e4460f7afd40de7021b 100644
--- a/reviewboard/static/rb/js/models/commentEditorModel.js
+++ b/reviewboard/static/rb/js/models/commentEditorModel.js
@@ -8,18 +8,22 @@
  * same region this comment is on, and more.
  */
 RB.CommentEditor = Backbone.Model.extend({
-    defaults: {
-        canDelete: false,
-        canEdit: gUserAuthenticated,
-        canSave: false,
-        editing: false,
-        comment: null,
-        dirty: false,
-        openIssue: gOpenAnIssue,
-        publishedComments: [],
-        publishedCommentsType: null,
-        statusText: '',
-        text: ''
+    defaults: function() {
+        var userSession = RB.UserSession.instance;
+
+        return {
+            canDelete: false,
+            canEdit: userSession.get('authenticated'),
+            canSave: false,
+            editing: false,
+            comment: null,
+            dirty: false,
+            openIssue: userSession.get('commentsOpenAnIssue'),
+            publishedComments: [],
+            publishedCommentsType: null,
+            statusText: '',
+            text: ''
+        }
     },
 
     initialize: function() {
diff --git a/reviewboard/static/rb/js/models/tests/commentEditorModelTests.js b/reviewboard/static/rb/js/models/tests/commentEditorModelTests.js
index 110c7f8de6a17ae25b000e500909c2e945a67935..d126b2b1524630dd2dd551fb4dbdc87015f7633c 100644
--- a/reviewboard/static/rb/js/models/tests/commentEditorModelTests.js
+++ b/reviewboard/static/rb/js/models/tests/commentEditorModelTests.js
@@ -15,6 +15,58 @@ describe('models/CommentEditor', function() {
         });
     });
 
+    describe('Attribute defaults', function() {
+        describe('canEdit', function() {
+            it('When logged in', function() {
+                RB.UserSession.instance.set('authenticated', true);
+
+                editor = new RB.CommentEditor();
+                expect(editor.get('canEdit')).toBe(true);
+            });
+
+            it('When logged out', function() {
+                RB.UserSession.instance.set('authenticated', false);
+
+                editor = new RB.CommentEditor();
+                expect(editor.get('canEdit')).toBe(false);
+            });
+
+            it('With explicitly set value', function() {
+                RB.UserSession.instance.set('authenticated', false);
+
+                editor = new RB.CommentEditor({
+                    canEdit: true
+                });
+                expect(editor.get('canEdit')).toBe(true);
+            });
+        });
+
+        describe('openIssue', function() {
+            it('When user preference is true', function() {
+                RB.UserSession.instance.set('commentsOpenAnIssue', true);
+
+                editor = new RB.CommentEditor();
+                expect(editor.get('openIssue')).toBe(true);
+            });
+
+            it('When user preference is false', function() {
+                RB.UserSession.instance.set('commentsOpenAnIssue', false);
+
+                editor = new RB.CommentEditor();
+                expect(editor.get('openIssue')).toBe(false);
+            });
+
+            it('With explicitly set value', function() {
+                RB.UserSession.instance.set('commentsOpenAnIssue', false);
+
+                editor = new RB.CommentEditor({
+                    openIssue: true
+                });
+                expect(editor.get('openIssue')).toBe(true);
+            });
+        });
+    });
+
     describe('Capability states', function() {
         describe('canDelete', function() {
             it('When not editing', function() {
diff --git a/reviewboard/static/rb/js/models/tests/reviewGroupModelTests.js b/reviewboard/static/rb/js/models/tests/reviewGroupModelTests.js
index 0e5c5d5f6d5ae6c40eee0700b8873ab65e4bb948..bb48dd5e2633279630f92efc1480b92597f3d0cc 100644
--- a/reviewboard/static/rb/js/models/tests/reviewGroupModelTests.js
+++ b/reviewboard/static/rb/js/models/tests/reviewGroupModelTests.js
@@ -6,6 +6,7 @@ describe('models/ReviewGroup', function() {
             group;
 
         beforeEach(function() {
+            RB.UserSession.instance = null;
             session = RB.UserSession.create({
                 username: 'testuser',
                 watchedReviewGroupsURL: url
diff --git a/reviewboard/static/rb/js/models/tests/reviewRequestModelTests.js b/reviewboard/static/rb/js/models/tests/reviewRequestModelTests.js
index 4e6c1ede8e486db8a1d4c7bf5e2b33df5d13dbb5..0141ee7344a3f2b7e866ebf3220a341a8b5e49d1 100644
--- a/reviewboard/static/rb/js/models/tests/reviewRequestModelTests.js
+++ b/reviewboard/static/rb/js/models/tests/reviewRequestModelTests.js
@@ -6,6 +6,7 @@ describe('models/ReviewRequest', function() {
             reviewRequest;
 
         beforeEach(function() {
+            RB.UserSession.instance = null;
             session = RB.UserSession.create({
                 username: 'testuser',
                 watchedReviewRequestsURL: url
diff --git a/reviewboard/static/rb/js/models/tests/userSessionModelTests.js b/reviewboard/static/rb/js/models/tests/userSessionModelTests.js
index de3b910948900d44a077e01a1d899612d483c292..5aefa4a8cd0d033463c0c51bc909ed2453155b5a 100644
--- a/reviewboard/static/rb/js/models/tests/userSessionModelTests.js
+++ b/reviewboard/static/rb/js/models/tests/userSessionModelTests.js
@@ -1,7 +1,10 @@
 describe('models/UserSession', function() {
     describe('create', function() {
         it('Instance is set', function() {
-            var session = RB.UserSession.create({
+            var session;
+
+            RB.UserSession.instance = null;
+            session = RB.UserSession.create({
                 username: 'testuser'
             });
 
@@ -9,6 +12,7 @@ describe('models/UserSession', function() {
         });
 
         it('Second attempt fails', function() {
+            RB.UserSession.instance = null;
             RB.UserSession.create({
                 username: 'testuser'
             });
diff --git a/reviewboard/static/rb/js/models/userSessionModel.js b/reviewboard/static/rb/js/models/userSessionModel.js
index fc5dd1f530d2e696fe47b6d972f70a11d5e1b29b..ab69d3d02e4a6d8d3fca3c5e3844e8f5975fa37a 100644
--- a/reviewboard/static/rb/js/models/userSessionModel.js
+++ b/reviewboard/static/rb/js/models/userSessionModel.js
@@ -53,25 +53,43 @@ var WatchedItems = RB.BaseResource.extend({
      * Immediately adds an object to a watched list on the server.
      */
     addImmediately: function(obj, options, context) {
-        var item = new Item({
-            objectID: obj.id,
-            baseURL: this.url()
-        });
-
-        item.save(options, context);
+        var url = this.url(),
+            item;
+
+        if (url) {
+            item = new Item({
+                objectID: obj.id,
+                baseURL: url
+            });
+
+            item.save(options, context);
+        } else if (options && _.isFunction(options.error)) {
+            options.error.call({
+                errorText: 'Must log in to add a watched item.'
+            });
+        }
     },
 
     /*
      * Immediately removes an object from a watched list on the server.
      */
     removeImmediately: function(obj, options, context) {
-        var proxyObj = new Item({
-            objectID: obj.id,
-            baseURL: this.url(),
-            watched: true
-        });
-
-        proxyObj.destroy(options, context);
+        var url = this.url(),
+            item;
+
+        if (url) {
+            var item = new Item({
+                objectID: obj.id,
+                baseURL: url,
+                watched: true
+            });
+
+            item.destroy(options, context);
+        } else if (options && _.isFunction(options.error)) {
+            options.error.call({
+                errorText: 'Must log in to add a watched item.'
+            });
+        }
     }
 });
 
@@ -88,7 +106,10 @@ var WatchedItems = RB.BaseResource.extend({
  */
 RB.UserSession = Backbone.Model.extend({
     defaults: {
+        authenticated: false,
+        fullName: null,
         username: null,
+        userPageURL: null,
         sessionURL: null,
         watchedReviewGroupsURL: null,
         watchedReviewRequestsURL: null
diff --git a/reviewboard/static/rb/js/reviews.js b/reviewboard/static/rb/js/reviews.js
index fa0b4a31f64ee5076df4bdb485868794d013a3c0..9e2a61b76856c553d2f5f01bd8c5064d822e2d00 100644
--- a/reviewboard/static/rb/js/reviews.js
+++ b/reviewboard/static/rb/js/reviews.js
@@ -382,7 +382,8 @@ $.fn.commentSection = function(review_id, context_id, context_type) {
      * Creates a new comment form in response to the "Add Comment" link.
      */
     function createNewCommentForm() {
-        var yourcomment_id = "yourcomment_" + review_id + "_" +
+        var userSession = RB.UserSession.instance,
+            yourcomment_id = "yourcomment_" + review_id + "_" +
                              context_type;
         if (sectionId) {
             yourcomment_id += "_" + sectionId;
@@ -398,8 +399,8 @@ $.fn.commentSection = function(review_id, context_id, context_type) {
                     .append($("<label/>")
                         .attr("for", yourcomment_id)
                         .append($("<a/>")
-                            .attr("href", gUserURL)
-                            .html(gUserFullName)
+                            .attr("href", userSession.get('userPageURL'))
+                            .html(userSession.get('fullName'))
                         )
                     )
                     .append('<dd><pre id="' + yourcomment_id + '"/></dd>')
@@ -1818,7 +1819,7 @@ $(document).ready(function() {
     $("#submitted-banner #changedescription.editable").reviewCloseCommentEditor(RB.ReviewRequest.CLOSE_SUBMITTED);
     $("#discard-banner #changedescription.editable").reviewCloseCommentEditor(RB.ReviewRequest.CLOSE_DISCARDED);
 
-    if (gUserAuthenticated) {
+    if (RB.UserSession.instance.get('authenticated')) {
         if (window["gEditable"]) {
             var dndUploader;
 
diff --git a/reviewboard/static/rb/js/views/tests/commentDialogViewTests.js b/reviewboard/static/rb/js/views/tests/commentDialogViewTests.js
index 0ace5be28bdfedf9e3b63d9b743f221088d27fb1..0539a2ba26140f3a275e90bf9ba14811abba3f52 100644
--- a/reviewboard/static/rb/js/views/tests/commentDialogViewTests.js
+++ b/reviewboard/static/rb/js/views/tests/commentDialogViewTests.js
@@ -485,5 +485,39 @@ describe('views/CommentDialogView', function() {
                 });
             });
         });
+
+        describe('User preference defaults', function() {
+            describe('Open Issue checkbox', function() {
+                it('When commentsOpenAnIssue is true', function() {
+                    RB.UserSession.instance.set('commentsOpenAnIssue', true);
+
+                    editor = new RB.CommentEditor();
+                    dlg = new RB.CommentDialogView({
+                        animate: false,
+                        model: editor
+                    });
+                    dlg.render();
+                    $checkbox = dlg.$el.find('input[type=checkbox]');
+
+                    expect(editor.get('openIssue')).toBe(true);
+                    expect($checkbox.prop('checked')).toBe(true);
+                });
+
+                it('When commentsOpenAnIssue is false', function() {
+                    RB.UserSession.instance.set('commentsOpenAnIssue', false);
+
+                    editor = new RB.CommentEditor();
+                    dlg = new RB.CommentDialogView({
+                        animate: false,
+                        model: editor
+                    });
+                    dlg.render();
+                    $checkbox = dlg.$el.find('input[type=checkbox]');
+
+                    expect(editor.get('openIssue')).toBe(false);
+                    expect($checkbox.prop('checked')).toBe(false);
+                });
+            });
+        });
     });
 });
diff --git a/reviewboard/templates/base.html b/reviewboard/templates/base.html
index 421baff443ce12f37c58c6cb51bff7ef76937c96..d9b138ad4aef589b023d8614b15d0d566536f93e 100644
--- a/reviewboard/templates/base.html
+++ b/reviewboard/templates/base.html
@@ -26,12 +26,7 @@
             'rb/images/spinner.gif': '{% static "rb/images/spinner.gif" %}',
             'rb/images/star_off.png': '{% static "rb/images/star_off.png" %}',
             'rb/images/star_on.png': '{% static "rb/images/star_on.png" %}'
-        },
-{% if not user.is_anonymous %}
-        gUserName = "{{user.username}}",
-        gUserFullName = "{{user|user_displayname}}",
-{% endif %}
-        gUserAuthenticated = {{user.is_authenticated|lower}};
+        };
 {% block jsconsts %}{% endblock %}
   </script>
   <link rel="shortcut icon" type="image/x-icon" href="{% static "rb/images/favicon.ico" %}" />
@@ -154,16 +149,22 @@
   {% compressed_js "3rdparty" %}
   <script type="text/javascript" src="{% static "djblets/js/jquery.gravy.js" %}"></script>
   {% compressed_js "common" %}
-{% if request.user.is_authenticated %}
   <script type="text/javascript">
     RB.UserSession.create({
-        username: "{{user.username|escapejs}}",
+{% if request.user.is_authenticated %}
+        authenticated: true,
+        commentsOpenAnIssue: {{request.user.get_profile.open_an_issue|lower}},
+        fullName: "{{request.user|user_displayname|escapejs}}",
+        username: "{{request.user.username|escapejs}}",
+        userPageURL: "{% url user request.user %}",
         sessionURL: "{% url session-resource %}",
         watchedReviewGroupsURL: "{% url watched-review-groups-resource request.user %}",
         watchedReviewRequestsURL: "{% url watched-review-requests-resource request.user %}"
+{% else %}
+        authenticated: false
+{% endif %}
     });
   </script>
-{% endif %}
 {% block scripts-post %}{% endblock %}
 {% template_hook_point "base-scripts-post" %}
  </body>
diff --git a/reviewboard/templates/js/tests.html b/reviewboard/templates/js/tests.html
index c89e9bff39157dcb928ff2cb09d4d691b89cef44..16d2a917bfff21d01cc2f983af1b6b83e81387ff 100644
--- a/reviewboard/templates/js/tests.html
+++ b/reviewboard/templates/js/tests.html
@@ -12,13 +12,11 @@
   /* XXX Ideally, these should all be optional. */
   var gBugTrackerURL = '',
       gEditable = false,
-      gOpenAnIssue = true,
       gReviewPending = false,
       gReviewRequestId = 1,
       gReviewRequestPath = "{{SITE_ROOT}}/r/1/",
       gReviewRequestSitePrefix = "{{SITE_ROOT}}",
-      gReviewRequestSummary = '',
-      gUserURL = "{{SITE_ROOT}}/users/test/";
+      gReviewRequestSummary = '';
 {% endblock %}
 
 {% block scripts-post %}
@@ -47,21 +45,30 @@ $(document).ready(function() {
 
     beforeEach(function() {
         /*
+         * Set the session to be authenticated by default. If tests need
+         * it to be unauthenticated, they can reset this.
+         */
+        RB.UserSession.instance = null;
+        RB.UserSession.create({
+            authenticated: true,
+            commentsOpenAnIssue: true,
+            username: 'testuser',
+            userPageURL: '{{SITE_ROOT}}users/test/'
+        });
+
+        /*
          * Capture all assertions, so we can sanely inspect them.
          * We don't want to call the original version, though, or we'll
          * possibly get errors in the console.
+         *
+         * We do this after creating the UserSession, since that will also
+         * assert.
          */
         spyOn(console, 'assert').andCallFake(function(condition, msg) {
             if (!condition) {
                 throw Error(msg);
             }
         });
-
-        /*
-         * Reset the user session, since tests should explicitly create it
-         * if it's needed.
-         */
-        RB.UserSession.instance = null;
     });
 
     afterEach(function() {
diff --git a/reviewboard/templates/reviews/reviewable_base.html b/reviewboard/templates/reviews/reviewable_base.html
index bcff064fbe2d25b3163f89050bf6833934b65e50..dd2517565da2443049383fe0c8953063d688f982 100644
--- a/reviewboard/templates/reviews/reviewable_base.html
+++ b/reviewboard/templates/reviews/reviewable_base.html
@@ -2,14 +2,6 @@
 {% load compressed %}
 {% load i18n %}
 
-{% block jsconsts %}
-{{block.super}}
-{%  if request.user.is_authenticated %}
-  var gUserURL = "{% url user request.user %}";
-  var gOpenAnIssue = {{user.get_profile.open_an_issue|lower}};
-{%  endif %}
-{% endblock %}
-
 {% block ie6_csshacks %}
    #review-banner .banner { position: absolute; }
 {% endblock %}
