diff --git a/app/models/Invite.js b/app/models/Invite.js
index 2159cb5..a558cbc 100644
--- a/app/models/Invite.js
+++ b/app/models/Invite.js
@@ -6,12 +6,36 @@ var InviteSchema = mongoose.Schema({
         unique: true,
         required: true
     },
-    scope: [String],
-    issuer: String,
-    recipient: String,
-    issued: Date,
-    used: Date,
-    exp: Date
+
+    scope: {
+        type: [String],
+        required: true
+    },
+
+    issuer: {
+        type: String,
+        required: true
+    },
+
+    recipient: {
+        type: String,
+        default: null
+    },
+
+    issued: {
+        type: Date,
+        default: Date.now
+    },
+
+    used: {
+        type: Date,
+        default: null
+    },
+
+    exp: {
+        type: Date,
+        default: null
+    }
 });
 
 /*InviteSchema.methods.use = function(canonicalname, cb) {
diff --git a/app/models/Key.js b/app/models/Key.js
index 03dea07..3df9395 100644
--- a/app/models/Key.js
+++ b/app/models/Key.js
@@ -1,22 +1,41 @@
-var mongoose = require('mongoose');
+const mongoose = require('mongoose');
+
+const KeySchema = mongoose.Schema({
+    key: {
+        type: String,
+        unique: true,
+        required: true
+    },
 
-var KeySchema = mongoose.Schema({
-    key: String,
     identifier: {
         type: String,
         required: true
     },
-    scope: [String],
+
+    scope: {
+        type: [String],
+        required: true,
+    },
+
     uploadCount: {
         type: Number,
         default: 0
     },
+
     uploadSize: {
         type: Number,
         default: 0
     },
-    username: String,
-    date: Date
+
+    issuer: {
+        type: String,
+        required: true
+    },
+
+    date: {
+        type: Date,
+        default: Date.now
+    }
 });
 
 module.exports = mongoose.model('Key', KeySchema);
\ No newline at end of file
diff --git a/app/models/User.js b/app/models/User.js
index 87a1e44..110b4cb 100644
--- a/app/models/User.js
+++ b/app/models/User.js
@@ -7,26 +7,36 @@ var UserSchema = mongoose.Schema({
         unique: true,
         required: true
     },
-    canonicalname: {
+
+    displayname: {
         type: String,
         unique: true,
         required: true
     },
-    scope: [String],
+
+    scope: {
+        type: [String],
+        required: true
+    },
+
     uploadCount: {
         type: Number,
         default: 0
     },
+
     uploadSize: {
         type: Number,
         default: 0
     },
-    date: Date
+
+    date: {
+        type: Date,
+        default: Date.now
+    }
 });
 
 UserSchema.plugin(passportLocalMongoose, {
-    usernameField: 'canonicalname',
-    saltlen: 32,
+    saltlen: 64,
     iterations: 10000,
     limitAttempts: true
 });
diff --git a/app/routes/auth.js b/app/routes/auth.js
index 640fea4..26ea4f3 100644
--- a/app/routes/auth.js
+++ b/app/routes/auth.js
@@ -1,17 +1,17 @@
-'use strict';
-
 const express = require('express');
 const router = express.Router();
-const User = require('../models/User.js');
-const Invite = require('../models/Invite.js');
-const passport = require('passport');
 const config = require('config');
 
+const ModelPath = '../models/';
+const User = require(ModelPath + 'User.js');
+const Invite = require(ModelPath + 'Invite.js');
+
+const passport = require('passport');
+
 const canonicalizeRequest = require('../util/canonicalize').canonicalizeRequest;
 const requireAuth = require('../util/requireAuth').requireAuth;
 const wrap = require('../util/wrap.js').wrap;
 
-
 // Wraps passport.authenticate to return a promise
 function authenticate(req, res, next) {
     return new Promise((resolve) => {
@@ -28,16 +28,16 @@ function login(user, req) {
     });
 }
 
-// Check if a canonical name is valid
-async function validateUsername(username, canonicalName, sanitize) {
-    if (canonicalName.length > config.get('User.Username.maxLength'))
+// Check if the requested username is valid
+async function validateUsername(username, sanitize) {
+    if (username.length > config.get('User.Username.maxLength'))
         return {valid: false, message: 'Username too long.'};
 
     const restrictedRegex = new RegExp(config.get('User.Username.restrictedChars'), 'g');
-    if (canonicalName !== sanitize(canonicalName).replace(restrictedRegex, ''))
+    if (username !== sanitize(username).replace(restrictedRegex, ''))
         return {valid: false, message: 'Username contains invalid characters.'};
 
-    const count = await User.countDocuments({canonicalname: canonicalName});
+    const count = await User.countDocuments({username: username});
 
     if (count !== 0)
         return {valid: false, message: 'Username in use.'};
@@ -55,19 +55,19 @@ async function validateInvite(code) {
     if (invite.used)
         return {valid: false, message: 'Invite already used.'};
 
-    if (invite.exp < Date.now())
+    if (invite.exp != null && invite.exp < Date.now())
         return {valid: false, message: 'Invite expired.'};
 
     return {valid: true, invite: invite};
 }
 
 
-router.post('/register', canonicalizeRequest, wrap(async (req, res, next) => {
+router.post('/register', canonicalizeRequest, wrap(async (req, res) => {
     // Validate the invite and username
     const [inviteStatus, usernameStatus] =
         await Promise.all([
             validateInvite(req.body.invite),
-            validateUsername(req.body.username, req.body.canonicalname, req.sanitize)
+            validateUsername(req.body.username, req.sanitize)
         ]);
 
     // Error if validation failed
@@ -80,11 +80,11 @@ router.post('/register', canonicalizeRequest, wrap(async (req, res, next) => {
     await Promise.all([
         User.register({
             username: req.body.username,
-            canonicalname: req.body.canonicalname,
+            displayname: req.body.displayname,
             scope: inviteStatus.invite.scope,
             date: Date.now()
         }, req.body.password),
-        Invite.updateOne({code: inviteStatus.invite.code}, {recipient: req.body.canonicalname, used: Date.now()})
+        Invite.updateOne({code: inviteStatus.invite.code}, {recipient: req.body.username, used: Date.now()})
     ]);
 
     res.status(200).json({'message': 'Registration successful.'});
@@ -100,7 +100,7 @@ router.post('/login', canonicalizeRequest, wrap(async (req, res, next) => {
     await login(user, req);
 
     // Set session vars
-    req.session.passport.display = user.username;
+    req.session.passport.displayname = user.displayname;
     req.session.passport.scope = user.scope;
 
     res.status(200).json({'message': 'Logged in.'});
@@ -113,10 +113,10 @@ router.post('/logout', function (req, res) {
 
 router.get('/whoami', requireAuth(), (req, res) => {
     res.status(200).json({
-        user: req.authUser,
-        display: req.authDisplay,
-        scope: req.authScope,
-        key: req.authKey
+        user: req.username,
+        display: req.displayname,
+        scope: req.scope,
+        key: req.key
     });
 });
 
diff --git a/app/routes/upload.js b/app/routes/upload.js
index 9dcf410..2f4b732 100644
--- a/app/routes/upload.js
+++ b/app/routes/upload.js
@@ -32,9 +32,9 @@ const generateId = async () => {
 
 const updateStats = async req =>
     Promise.all([
-        User.updateOne({username: req.authUser}, {$inc: {uploadCount: 1, uploadSize: req.file.size}}),
-        req.authKey
-            ? Key.updateOne({key: req.authKey}, {$inc: {uploadCount: 1, uploadSize: req.file.size}})
+        User.updateOne({username: req.username}, {$inc: {uploadCount: 1, uploadSize: req.file.size}}),
+        req.key
+            ? Key.updateOne({key: req.key}, {$inc: {uploadCount: 1, uploadSize: req.file.size}})
             : Promise.resolve()
     ]);
 
@@ -50,8 +50,8 @@ router.post('/', requireAuth('file.upload'), fileUpload, wrap(async (req, res) =
 
     const upload = {
         id: await generateId(),
-        uploader: req.authUser,
-        uploaderKey: req.authKey,
+        uploader: req.username,
+        uploaderKey: req.key,
         date: Date.now(),
         file: req.file
     };
diff --git a/app/util/canonicalize.js b/app/util/canonicalize.js
index e27df4c..1649891 100644
--- a/app/util/canonicalize.js
+++ b/app/util/canonicalize.js
@@ -1,8 +1,8 @@
 // Normalizes, decomposes, and lowercases a utf-8 string
-exports.canonicalize = (username) => username.normalize('NFKD').toLowerCase();
+exports.canonicalize = displayname => displayname.normalize('NFKD').toLowerCase();
 
 exports.canonicalizeRequest =
     (req, res, next) => {
-        req.body.canonicalname = exports.canonicalize(req.body.username);
+        req.body.username = exports.canonicalize(req.body.displayname);
         next();
     };
\ No newline at end of file
diff --git a/app/util/requireAuth.js b/app/util/requireAuth.js
index a21ca8d..fe7be9e 100644
--- a/app/util/requireAuth.js
+++ b/app/util/requireAuth.js
@@ -12,10 +12,10 @@ exports.requireAuth = scope =>
     wrap(async (req, res, next) => {
         if (req.isAuthenticated()) {
             if (scope ? verifyScope(req.session.passport.scope, scope) : true) {
-                req.authUser = req.session.passport.user;
-                req.authDisplay = req.session.passport.display;
-                req.authScope = req.session.passport.scope;
-                req.authKey = null;
+                req.username = req.session.passport.user;
+                req.displayname = req.session.passport.displayname;
+                req.scope = req.session.passport.scope;
+                req.key = null;
                 next();
             } else {
                 res.status(403).json({message: 'Forbidden.'});
@@ -23,10 +23,10 @@ exports.requireAuth = scope =>
         } else if (req.body.apikey) {
             const key = await Key.findOne({key: apikey});
             if (scope ? verifyScope(key.scope, scope) : true) {
-                req.authUser = key.username;
-                req.authDisplay = key.username;
-                req.authScope = key.scope;
-                req.authKey = key.key;
+                req.username = key.username;
+                req.displayname = key.username;
+                req.scope = key.scope;
+                req.key = key.key;
                 next();
             } else {
                 res.status(403).json({message: 'Forbidden.'});
diff --git a/test/api.js b/test/api.js
index b04a21d..7b884ed 100644
--- a/test/api.js
+++ b/test/api.js
@@ -2,6 +2,7 @@ process.env.NODE_ENV = 'test';
 
 const chai = require('chai');
 chai.use(require('chai-http'));
+const should = chai.should();
 
 const ModelPath = '../app/models/';
 const User = require(ModelPath + 'User.js');
@@ -43,26 +44,26 @@ describe('Accounts', function() {
                 res.body.should.be.a('object');
                 res.body.should.have.property('message').eql('Registration successful.');
 
-                const userCount = await User.countDocuments({username: user.username});
+                const userCount = await User.countDocuments({displayname: user.displayname});
                 userCount.should.equal(1);
 
-                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.username)});
+                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.displayname)});
                 inviteCount.should.equal(1);
             }
 
             it('MUST register a valid user with a valid invite', async () =>
-                verifySuccessfulRegister({username: 'user', password: 'pass', invite: 'code'})
+                verifySuccessfulRegister({displayname: 'user', password: 'pass', invite: 'code'})
             );
 
             it('MUST register a username with unicode symbols and a valid invite', async () =>
-                verifySuccessfulRegister({username: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'pass', invite: 'code'})
+                verifySuccessfulRegister({displayname: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'pass', invite: 'code'})
             );
         });
 
 
         describe('1 Invalid Invites', () => {
             async function verifyRejectedInvite(invite, message) {
-                const user = {username: 'user', password: 'pass', invite: 'code'};
+                const user = {displayname: 'user', password: 'pass', invite: 'code'};
                 if (invite) {
                     await util.createInvite(invite, agent);
                     user.invite = invite.code;
@@ -73,7 +74,7 @@ describe('Accounts', function() {
                 res.body.should.be.a('object');
                 res.body.should.have.property('message').eql(message);
 
-                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.username)});
+                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.displayname)});
                 inviteCount.should.equal(0);
             }
 
@@ -82,30 +83,30 @@ describe('Accounts', function() {
             );
 
             it('MUST NOT register a used invite', async () =>
-                verifyRejectedInvite({code: 'code', used: new Date()}, 'Invite already used.')
+                verifyRejectedInvite({code: 'code', used: new Date(), issuer: 'Mocha'}, 'Invite already used.')
             );
 
             it('MUST NOT register an expired invite', async () =>
-                verifyRejectedInvite({code: 'code', exp: new Date()}, 'Invite expired.')
+                verifyRejectedInvite({code: 'code', exp: new Date(), issuer: 'Mocha'}, 'Invite expired.')
             );
         });
 
 
-        describe('2 Invalid Usernames', () => {
+        describe('2 Invalid Displaynames', () => {
             async function verifyRejectedUsername(user, message) {
                 const res = await util.registerUser(user, agent);
                 res.should.have.status(422);
                 res.body.should.be.a('object');
                 res.body.should.have.property('message').equal(message);
 
-                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.username)});
+                const inviteCount = await Invite.countDocuments({code: user.invite, recipient: canonicalize(user.displayname)});
                 inviteCount.should.equal(0);
             }
 
             it('MUST NOT register a duplicate username', async () => {
                 await util.createTestInvites(2);
-                const user0 = {username: 'user', password: 'pass', invite: 'code0'};
-                const user1 = {username: 'user', password: 'diff', invite: 'code1'};
+                const user0 = {displayname: 'user', password: 'pass', invite: 'code0'};
+                const user1 = {displayname: 'user', password: 'diff', invite: 'code1'};
 
                 await util.registerUser(user0, agent);
                 return verifyRejectedUsername(user1, 'Username in use.');
@@ -113,8 +114,8 @@ describe('Accounts', function() {
 
             it('MUST NOT register a username with a duplicate canonical name', async () => {
                 await util.createTestInvites(2);
-                const user0 = {username: 'bigbird', password: 'pass', invite: 'code0'};
-                const user1 = {username: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'diff', invite: 'code1'};
+                const user0 = {displayname: 'bigbird', password: 'pass', invite: 'code0'};
+                const user1 = {displayname: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'diff', invite: 'code1'};
 
                 await util.registerUser(user0, agent);
                 return verifyRejectedUsername(user1, 'Username in use.');
@@ -123,9 +124,9 @@ describe('Accounts', function() {
             it('MUST NOT register a username containing whitespace', async () => {
                 await util.createTestInvites(3);
                 const users = [
-                    {username: 'user name', password: 'pass', invite: 'code0'},
-                    {username: 'user name', password: 'pass', invite: 'code1'},
-                    {username: 'user name', password: 'pass', invite: 'code2'}
+                    {displayname: 'user name', password: 'pass', invite: 'code0'},
+                    {displayname: 'user name', password: 'pass', invite: 'code1'},
+                    {displayname: 'user name', password: 'pass', invite: 'code2'}
                 ];
 
                 const failMsg = 'Username contains invalid characters.';
@@ -134,13 +135,13 @@ describe('Accounts', function() {
 
             it('MUST NOT register a username containing HTML', async () => {
                 await util.createTestInvite();
-                const user = {username: 'user<svg/onload=alert("XSS")>', password: 'pass', invite: 'code'};
+                const user = {displayname: 'user<svg/onload=alert("XSS")>', password: 'pass', invite: 'code'};
                 return verifyRejectedUsername(user, 'Username contains invalid characters.');
             });
 
             it('MUST NOT register a username with too many characters', async () => {
                 await util.createTestInvite();
-                const user = {username: '123456789_123456789_123456789_1234567', password: 'pass', invite: 'code'};
+                const user = {displayname: '123456789_123456789_123456789_1234567', password: 'pass', invite: 'code'};
                 return verifyRejectedUsername(user, 'Username too long.');
             })
         });
@@ -167,7 +168,7 @@ describe('Accounts', function() {
         describe('0 Valid Request', () => {
             it('SHOULD accept a valid user with a valid password', async () => {
                 await util.createTestUser(agent);
-                return verifySuccessfulLogin({username: 'user', password: 'pass'});
+                return verifySuccessfulLogin({displayname: 'user', password: 'pass'});
             });
 
             it('SHOULD accept any non-normalized variant of a username with a valid password', async () => {
@@ -179,13 +180,13 @@ describe('Accounts', function() {
         describe('1 Invalid Password', () => {
             it('SHOULD NOT accept an invalid password', async () => {
                 await util.createTestUser(agent);
-                return verifyFailedLogin({username: 'user', password: 'bogus'});
+                return verifyFailedLogin({displayname: 'user', password: 'bogus'});
             });
         });
 
         describe('2 Invalid User', () => {
             it('SHOULD NOT accept an invalid user', async () =>
-                verifyFailedLogin({username: 'bogus', password: 'bogus'})
+                verifyFailedLogin({displayname: 'bogus', password: 'bogus'})
             );
         });
     });
@@ -195,12 +196,12 @@ describe('Uploads', () => {
     beforeEach(async () => util.clearDatabase());
 
     describe('/POST upload', () => {
-        async function verifySuccessfulUpload(file, user) {
+        async function verifySuccessfulUpload(file, username) {
             // Get file stats beforehand
             const [fileHash, fileSize] = await Promise.all([util.fileHash(file), util.fileSize(file)]);
 
             // Get the user stats beforehand
-            const userBefore = await User.findOne({canonicalname: user}, {_id: 0, uploadCount: 1, uploadSize: 1});
+            const userBefore = await User.findOne({username: username}, {_id: 0, uploadCount: 1, uploadSize: 1});
 
             // Submit the upload and verify the result
             const res = await util.upload(file, agent);
@@ -221,11 +222,15 @@ describe('Uploads', () => {
             uploadSize.should.equal(fileSize);
 
             // Verify the user's stats have been updated correctly
-            const userAfter = await User.findOne({canonicalname: user}, {_id: 0, uploadCount: 1, uploadSize: 1});
+            const userAfter = await User.findOne({username: username}, {_id: 0, uploadCount: 1, uploadSize: 1});
             userAfter.uploadCount.should.equal(userBefore.uploadCount + 1);
             userAfter.uploadSize.should.equal(userBefore.uploadSize + fileSize);
         }
 
+        async function verifySuccessfulKeyUpload(key, file) {
+
+        }
+
         async function verifyFailedUpload(file, status, message) {
             const fileCountBefore = await util.directoryFileCount(config.get('Upload.path'));
             const uploadCountBefore = await Upload.countDocuments({});
@@ -264,9 +269,9 @@ describe('Uploads', () => {
             );
 
             it('SHOULD NOT accept a request without file.upload scope', async () => {
-                await util.createInvite({code: 'code', scope: []});
-                await util.registerUser({username: 'user', password: 'pass', invite: 'code'}, agent);
-                await util.login({username: 'user', password: 'pass'}, agent);
+                await util.createInvite({code: 'code', scope: [], issuer: 'Mocha'});
+                await util.registerUser({displayname: 'user', password: 'pass', invite: 'code'}, agent);
+                await util.login({displayname: 'user', password: 'pass'}, agent);
 
                 await util.createTestFile(2048, 'test.bin');
 
diff --git a/test/testUtil.js b/test/testUtil.js
index ca92dcd..7f10c19 100644
--- a/test/testUtil.js
+++ b/test/testUtil.js
@@ -2,12 +2,12 @@ process.env.NODE_ENV = 'test';
 
 const chai = require('chai');
 chai.use(require('chai-http'));
-const should = chai.should();
 
-const User = require('../app/models/User.js');
-const Invite = require('../app/models/Invite.js');
-const Upload = require('../app/models/Upload.js');
-const Key = require('../app/models/Key.js');
+const ModelPath = '../app/models/';
+const User = require(ModelPath + 'User.js');
+const Upload = require(ModelPath + 'Upload.js');
+const Key = require(ModelPath + 'Key.js');
+const Invite = require(ModelPath + 'Invite.js');
 
 const Buffer = require('buffer').Buffer;
 const crypto = require('crypto');
@@ -51,22 +51,22 @@ exports.whoami = (agent) =>
 //---------------- TEST ENTRY CREATION ----------------//
 
 exports.createTestInvite = () =>
-    exports.createInvite({code: 'code', scope: ['file.upload']});
+    exports.createInvite({code: 'code', scope: ['file.upload'], issuer: 'Mocha'});
 
 exports.createTestInvites = (n) =>
     Promise.all(
         Array.from(new Array(n), (val, index) => 'code' + index)
-            .map(code => exports.createInvite({code: code}))
+            .map(code => exports.createInvite({code: code, scope: ['file.upload'], issuer: 'Mocha'}))
     );
 
 exports.createTestUser = async agent => {
     await exports.createTestInvite();
-    return exports.registerUser({username: 'user', password: 'pass', invite: 'code'}, agent);
+    return exports.registerUser({displayname: 'user', password: 'pass', invite: 'code'}, agent);
 };
 
 exports.createTestSession = async agent => {
     await exports.createTestUser(agent);
-    return exports.login({username: 'user', password: 'pass'}, agent);
+    return exports.login({displayname: 'user', password: 'pass'}, agent);
 };
 
 exports.createTestFile = (size, name) =>