diff --git a/epochs.py b/epochs.py
index b90c1b5b31cd01728d1dd73ac58f50a7d66095bb..18d46f690229a0246e51423a236131f957087161 100644
--- a/epochs.py
+++ b/epochs.py
@@ -19,15 +19,13 @@ class Epochs(nimsapiutil.NIMSRequestHandler):
 
     def get(self, sess_id):
         """Return the list of Session Epochs."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
         session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sess_id)})
         if not session:
             self.abort(404)
         experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])})
         if not experiment:
             self.abort(500)
-        if user not in experiment['permissions']:
+        if not self.user_is_superuser and self.userid not in experiment['permissions']:
             self.abort(403)
         query = {'session': bson.objectid.ObjectId(sess_id)}
         projection = ['timestamp', 'series', 'acquisition', 'description', 'datatype']
@@ -43,8 +41,6 @@ class Epoch(nimsapiutil.NIMSRequestHandler):
 
     def get(self, epoch_id):
         """Return one Epoch, conditionally with details."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
         epoch = self.app.db.epochs.find_one({'_id': bson.objectid.ObjectId(epoch_id)})
         if not epoch:
             self.abort(404)
@@ -54,7 +50,7 @@ class Epoch(nimsapiutil.NIMSRequestHandler):
         experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])})
         if not experiment:
             self.abort(500)
-        if user not in experiment['permissions']:
+        if not self.user_is_superuser and self.userid not in experiment['permissions']:
             self.abort(403)
         self.response.write(json.dumps(epoch, default=bson.json_util.default))
 
diff --git a/experiments.py b/experiments.py
index 18f5cf826b110e5425bc81483ec36bbbc52aa8dd..ea6e9c47399efdd92a8f2ceddec56ae6b8995c38 100644
--- a/experiments.py
+++ b/experiments.py
@@ -19,10 +19,8 @@ class Experiments(nimsapiutil.NIMSRequestHandler):
 
     def get(self):
         """Return the list of Experiments."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
-        query = {'permissions.' + user: {'$exists': 'true'}}
-        projection = ['timestamp', 'group', 'name', 'permissions.'+user]
+        query = {'permissions.' + self.userid: {'$exists': 'true'}} if not self.user_is_superuser else None
+        projection = ['timestamp', 'group', 'name', 'permissions.'+self.userid]
         experiments = list(self.app.db.experiments.find(query, projection))
         self.response.write(json.dumps(experiments, default=bson.json_util.default))
 
@@ -35,16 +33,14 @@ class Experiment(nimsapiutil.NIMSRequestHandler):
 
     def get(self, exp_id):
         """Return one Experiment, conditionally with details."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
-        query = {'_id': bson.objectid.ObjectId(exp_id), 'permissions.' + user: {'$exists': 'true'}}
         experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(exp_id)})
         if not experiment:
             self.abort(404)
-        if user not in experiment['permissions']:
-            self.abort(403)
-        if experiment['permissions'][user] != 'admin' and experiment['permissions'][user] != 'pi':
-            experiment['permissions'] = {user: experiment['permissions'][user]}
+        if not self.user_is_superuser:
+            if self.userid not in experiment['permissions']:
+                self.abort(403)
+            if experiment['permissions'][self.userid] != 'admin' and experiment['permissions'][self.userid] != 'pi':
+                experiment['permissions'] = {self.userid: experiment['permissions'][self.userid]}
         self.response.write(json.dumps(experiment, default=bson.json_util.default))
 
     def put(self, exp_id):
diff --git a/nimsapi.py b/nimsapi.py
index e24b8a0b50093cd0a6511da4bd21fe88148167bd..df2ee703b7c5ea1b0dee1fe7c41f2d74b31d85b8 100755
--- a/nimsapi.py
+++ b/nimsapi.py
@@ -88,7 +88,25 @@ class User(nimsapiutil.NIMSRequestHandler):
 
     def put(self, uid):
         """Update an existing User."""
-        self.response.write('user %s put, %s\n' % (uid, self.request.params))
+        user = self.app.db.users.find_one({'_id': uid})
+        if not user:
+            self.abort(404)
+        if uid == self.userid or self.user_is_superuser: # users can only update their own info
+            updates = {'$set': {}, '$unset': {}}
+            for k, v in self.request.params.iteritems():
+                if k != 'superuser' and k in user_fields:
+                    updates['$set'][k] = v # FIXME: do appropriate type conversion
+                elif k == 'superuser' and uid == self.userid and self.user_is_superuser is not None: # toggle superuser for requesting user
+                    updates['$set'][k] = v.lower() in ('1', 'true')
+                elif k == 'superuser' and uid != self.userid and self.user_is_superuser:             # enable/disable superuser for other user
+                    if v.lower() in ('1', 'true') and user.get('superuser') is None:
+                        updates['$set'][k] = False # superuser is tri-state: False indicates granted, but disabled, superuser privileges
+                    elif v.lower() not in ('1', 'true'):
+                        updates['$unset'][k] = ''
+            user = self.app.db.users.find_and_modify({'_id': uid}, updates, new=True)
+        else:
+            self.abort(403)
+        self.response.write(json.dumps(user, default=bson.json_util.default) + '\n')
 
     def delete(self, uid):
         """Delete an User."""
diff --git a/nimsapiutil.py b/nimsapiutil.py
index ec4691cde561bdf14029ef61eb803b7c1d03552f..c4acbcafc0b725f6c21bcefb392ebd9f76de8adc 100644
--- a/nimsapiutil.py
+++ b/nimsapiutil.py
@@ -7,4 +7,8 @@ class NIMSRequestHandler(webapp2.RequestHandler):
 
     def __init__(self, request=None, response=None):
         webapp2.RequestHandler.__init__(self, request, response)
+        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
+        self.userid = self.request.remote_user or '@public'
+        self.user = self.app.db.users.find_one({'_id': self.userid})
+        self.user_is_superuser = self.user.get('superuser')
         self.response.headers['Content-Type'] = 'application/json'
diff --git a/sessions.py b/sessions.py
index e1349062218ef90bcb5458ed6d4fedb8dc8678b5..d79f6bb454cf18d37e24728ffee0fd8b0c9afd87 100644
--- a/sessions.py
+++ b/sessions.py
@@ -19,12 +19,10 @@ class Sessions(nimsapiutil.NIMSRequestHandler):
 
     def get(self, exp_id):
         """Return the list of Experiment Sessions."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
         experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(exp_id)})
         if not experiment:
             self.abort(404)
-        if user not in experiment['permissions']:
+        if not self.user_is_superuser and self.userid not in experiment['permissions']:
             self.abort(403)
         query = {'experiment': bson.objectid.ObjectId(exp_id)}
         projection = ['timestamp', 'subject']
@@ -40,15 +38,13 @@ class Session(nimsapiutil.NIMSRequestHandler):
 
     def get(self, sess_id):
         """Return one Session, conditionally with details."""
-        self.request.remote_user = self.request.get('user', None) # FIXME: auth system should set REMOTE_USER
-        user = self.request.remote_user or '@public'
         session = self.app.db.sessions.find_one({'_id': bson.objectid.ObjectId(sess_id)})
         if not session:
             self.abort(404)
         experiment = self.app.db.experiments.find_one({'_id': bson.objectid.ObjectId(session['experiment'])})
         if not experiment:
             self.abort(500)
-        if user not in experiment['permissions']:
+        if not self.user_is_superuser and self.userid not in experiment['permissions']:
             self.abort(403)
         self.response.write(json.dumps(session, default=bson.json_util.default))