Implemented UsergridUser.login(), .logout() and .logoutAllSessions()

UsergridClient.authenticateUser() now leverages UsergridUser.login()
diff --git a/helpers/build.js b/helpers/build.js
index 39d062f..dc2ab9a 100644
--- a/helpers/build.js
+++ b/helpers/build.js
@@ -11,13 +11,35 @@
 module.exports = {
     url: function(client, options) {
         return urljoin(
-            config.baseUrl,
+            client.baseUrl,
             client.orgId,
             client.appId,
             options.type,
             _.isString(options.uuidOrName) ? options.uuidOrName : ""
         )
     },
+    userLoginBody: function(options) {
+        var body = {
+            grant_type: 'password',
+            password: options.password
+        }
+        if (options.tokenTtl) {
+            body.ttl = options.tokenTtl
+        }
+        body[(options.username) ? "username" : "email"] = (options.username) ? options.username : options.email
+        return body
+    },
+    appLoginBody: function(options) {
+        var body = {
+            grant_type: 'client_credentials',
+            client_id: options.clientId,
+            client_secret: options.clientSecret
+        }
+        if (options.tokenTtl) {
+            body.ttl = options.tokenTtl
+        }
+        return body
+    },
     GET: function(client, args) {
 
         /* GET supports the following constructor patterns:
@@ -150,8 +172,7 @@
             throw new Error('"body" parameter is required when making a POST request')
         }
 
-        options.body = _.isArray(options.body) ? options.body : [options.body]
-        options.type = _.first([options.type, args[0], options.body[0].type].filter(_.isString))
+        options.type = _.first([options.type, args[0], ok(options).getIfExists('body.0.type'), options.body.type].filter(_.isString))
 
         return options
     },
diff --git a/lib/appAuth.js b/lib/appAuth.js
index 00574c1..493415d 100644
--- a/lib/appAuth.js
+++ b/lib/appAuth.js
@@ -4,17 +4,15 @@
     util = require('util'),
     _ = require('lodash')
 
-var UsergridAppAuth = function() {
+var UsergridAppAuth = function(options) {
     var self = this
-
-    var args = Array.prototype.slice.call(arguments)
-    if (typeof args[0] === 'object') {
-        args = args[0]
+    var args = _.flatten(Array.prototype.slice.call(arguments), true)
+    if (_.isPlainObject(args[0])) {
+        options = args[0]
     }
-
-    self.clientId = args.clientId || args[0]
-    self.clientSecret = args.clientSecret || args[1]
-    self.tokenTtl = args.tokenTtl || args[2]
+    self.clientId = options.clientId || args[0]
+    self.clientSecret = options.clientSecret || args[1]
+    self.tokenTtl = options.tokenTtl || args[2]
     UsergridAuth.call(self)
     _.assign(self, UsergridAuth)
     return self
diff --git a/lib/auth.js b/lib/auth.js
index b54f3c8..06033c2 100644
--- a/lib/auth.js
+++ b/lib/auth.js
@@ -27,7 +27,19 @@
         configurable: true
     })
 
+    Object.defineProperty(self, 'tokenTtl', {
+        configurable: true
+    })
+
     return self
 }
 
+UsergridAuth.prototype = {
+    destroy: function() {
+        this.token = undefined
+        this.expiry = 0
+        this.tokenTtl = undefined
+    }
+}
+
 module.exports = UsergridAuth
\ No newline at end of file
diff --git a/lib/client.js b/lib/client.js
index c14ed38..4f8e927 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -119,9 +119,7 @@
         var self = this
         callback = helpers.cb(callback || options)
 
-        var auth = _.first([options, self.appAuth, new UsergridAppAuth(options)].filter(function(auth) {
-            return (auth instanceof UsergridAppAuth)
-        }))
+        var auth = (options instanceof UsergridAppAuth) ? options : self.appAuth || new UsergridAppAuth(options)
 
         if (!(auth instanceof UsergridAppAuth)) {
             throw new Error('App auth context was not defined when attempting to call .authenticateApp()')
@@ -134,11 +132,7 @@
         request({
             uri: helpers.build.url(self, auth),
             headers: helpers.userAgent,
-            body: {
-                grant_type: 'client_credentials',
-                client_id: auth.clientId,
-                client_secret: auth.clientSecret
-            },
+            body: helpers.build.appLoginBody(auth),
             method: 'POST',
             json: true
         }, function(error, response, body) {
@@ -159,40 +153,13 @@
         var self = this
         callback = helpers.cb(callback || options)
 
-        if (!options.username && !options.email && !options.password) {
-            throw new Error('authenticateUser() failed because username/email and password are missing')
-        } else if (!options.password) {
-            throw new Error('authenticateUser() failed because password is missing')
-        }
-
-        options.type = 'token'
-
-        request({
-            uri: helpers.build.url(self, options),
-            headers: helpers.userAgent,
-            body: options.username ? {
-                grant_type: 'password',
-                username: options.username,
-                password: options.password
-            } : {
-                grant_type: 'password',
-                email: options.email,
-                password: options.password
-            },
-            method: 'POST',
-            json: true
-        }, function(error, response, body) {
+        var UsergridUser = require('./user')
+        var currentUser = new UsergridUser(options)
+        currentUser.login(self, function(error, response, token) {
             if (response.statusCode === 200) {
-                var UsergridUser = require('./user')
-                self.currentUser = new UsergridUser(body.user)
-                self.currentUser.auth = new UsergridUserAuth(body.user)
-                self.currentUser.auth.token = body.access_token
-                self.currentUser.auth.expiry = helpers.time.expiry(body.expires_in)
-                self.currentUser.auth.tokenTtl = body.expires_in
-            } else {
-                error = new UsergridResponseError(response.body)
+                self.currentUser = currentUser
             }
-            callback(error, response, body.access_token)
+            callback(error, response, token)
         })
     }
 }
diff --git a/lib/request.js b/lib/request.js
index ccc2250..67a35de 100644
--- a/lib/request.js
+++ b/lib/request.js
@@ -19,7 +19,6 @@
             authorization: util.format("Bearer %s", options.client.appAuth.token)
         })
     }
-
     request(helpers.build.url(options.client, options), {
         headers: headers,
         body: options.body,
diff --git a/lib/responseError.js b/lib/responseError.js
index e03595f..1de62b9 100644
--- a/lib/responseError.js
+++ b/lib/responseError.js
@@ -7,7 +7,7 @@
         return
     }
     this.name = responseErrorObject.error
-    this.description = responseErrorObject.description || responseErrorObject.error_description
+    this.description = responseErrorObject.error_description || responseErrorObject.description
     this.exception = responseErrorObject.exception
     return this
 }
diff --git a/lib/user.js b/lib/user.js
index 21949f2..b3d5719 100644
--- a/lib/user.js
+++ b/lib/user.js
@@ -1,6 +1,9 @@
 'use strict'
 
 var UsergridEntity = require('./entity'),
+    UsergridUserAuth = require('./userAuth'),
+    UsergridResponseError = require('./responseError'),
+    request = require('request'),
     helpers = require('../helpers'),
     ok = require('objectkit'),
     util = require('util'),
@@ -14,6 +17,7 @@
     }
 
     var self = this
+    self.type = "user"
 
     _.assign(self, UsergridEntity.call(self, obj))
 
@@ -21,6 +25,78 @@
     return self
 }
 
+UsergridUser.prototype = {
+    create: function() {
+        var self = this
+        var args = Array.prototype.slice.call(arguments)
+        var client = helpers.client.validate(args)
+        var callback = helpers.cb(_.last(args.filter(_.isFunction)))
+        client.POST(self, function(err, usergridResponse) {
+            delete self.password
+            _.assign(self, usergridResponse.entity)
+            callback(err || usergridResponse.error, usergridResponse, usergridResponse.user)
+        }.bind(self))
+    },
+    login: function() {
+        var self = this
+        var args = Array.prototype.slice.call(arguments)
+        var client = helpers.client.validate(args)
+        var callback = helpers.cb(_.last(args.filter(_.isFunction)))
+        client.POST('token', helpers.build.userLoginBody(self), function(error, response) {
+            delete self.password
+            if (response.statusCode === 200) {
+                self.auth = new UsergridUserAuth(response.body.user)
+                self.auth.token = response.body.access_token
+                self.auth.expiry = helpers.time.expiry(response.body.expires_in)
+                self.auth.tokenTtl = response.body.expires_in
+            } else {
+                error = new UsergridResponseError(response.body)
+            }
+            callback(error || response.error, response, response.body.access_token)
+        }.bind(self))
+    },
+    logout: function() {
+        var self = this
+        var args = _.flatten(Array.prototype.slice.call(arguments), true)
+        var callback = helpers.cb(_.last(args.filter(_.isFunction)))
+        if (!self.auth || !self.auth.isValid) {
+            return callback({
+                name: 'no_valid_token',
+                description: 'this user does not have a valid token'
+            })
+        }
+        var client = helpers.client.validate(args)
+        var path
+        var revokeAll = _.first(args.filter(_.isBoolean)) || false
+        var userId = _.first([self.uuid, self.username, self.email].filter(_.isString))
+        var url = util.format("%s%s/revoketoken%s", helpers.build.url(client, {
+            type: 'user'
+        }), userId, (revokeAll) ? "s" : "")
+        request(url, {
+            headers: helpers.userAgent,
+            json: true,
+            method: 'PUT',
+            qs: (!revokeAll) ? {
+                token: self.auth.token
+            } : undefined
+        }, function(error, response) {
+            var UsergridResponse = require('./response'),
+                usergridResponse = new UsergridResponse(response)
+            if (usergridResponse.statusCode === 200) {
+                self.auth.destroy()
+            } else {
+                error = new UsergridResponseError(response.body)
+            }
+            callback(error || usergridResponse.error, usergridResponse, (usergridResponse.statusCode === 200))
+        })
+    },
+    logoutAllSessions: function() {
+        var args = Array.prototype.slice.call(arguments)
+        args.unshift(true)
+        return this.logout.apply(this, args)
+    }
+}
+
 util.inherits(UsergridUser, UsergridEntity)
 
 module.exports = UsergridUser
\ No newline at end of file
diff --git a/lib/userAuth.js b/lib/userAuth.js
index ca5200f..33cde69 100644
--- a/lib/userAuth.js
+++ b/lib/userAuth.js
@@ -6,13 +6,16 @@
 
 var UsergridUserAuth = function(options) {
     var self = this
-
-    self.email = options.email
-    self.username = options.username
-    if (options.password) {
-        self.password = options.password
+    var args = _.flatten(Array.prototype.slice.call(arguments), true)
+    if (_.isPlainObject(args[0])) {
+        options = args[0]
     }
-    self.tokenTtl = options.tokenTtl
+    self.username = options.username || args[0]
+    self.email = options.email
+    if (options.password || args[1]) {
+        self.password = options.password || args[1]
+    }
+    self.tokenTtl = options.tokenTtl || args[2]
     UsergridAuth.call(self)
     _.assign(self, UsergridAuth)
     return self
diff --git a/package.json b/package.json
index d795630..eac06af 100644
--- a/package.json
+++ b/package.json
@@ -1,31 +1,32 @@
 {
-    "author": "Brandon Shelley",
-    "dependencies": {
-        "async": "latest",
-        "lodash": "latest",
-        "lodash-inflection": "latest",
-        "lodash-uuid": "latest",
-        "objectkit": "latest",
-        "request": "latest",
-        "url-join": "latest"
-    },
-    "description": "The official Node.js SDK for Usergrid",
-    "devDependencies": {
-        "mocha": "latest",
-        "should": "latest"
-    },
-    "repository": {
-        "type": "git",
-        "url": "git://github.com/r3mus/usergrid-nodejs.git"
-    },
-    "keywords": [],
-    "license": "MIT",
-    "main": "app.js",
-    "name": "usergrid",
-    "private": false,
-    "scripts": {
-        "start": "node app.js",
-        "test": "mocha tests"
-    },
-    "version": "2.0.0-rc.1"
-}
\ No newline at end of file
+  "author": "Brandon Shelley",
+  "dependencies": {
+    "async": "latest",
+    "lodash": "latest",
+    "lodash-inflection": "latest",
+    "lodash-uuid": "latest",
+    "objectkit": "latest",
+    "request": "latest",
+    "url-join": "latest"
+  },
+  "description": "The official Node.js SDK for Usergrid",
+  "devDependencies": {
+    "chance": "^0.8.0",
+    "mocha": "latest",
+    "should": "latest"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/r3mus/usergrid-nodejs.git"
+  },
+  "keywords": [],
+  "license": "MIT",
+  "main": "app.js",
+  "name": "usergrid",
+  "private": false,
+  "scripts": {
+    "start": "node app.js",
+    "test": "mocha tests"
+  },
+  "version": "2.0.0-rc.1"
+}
diff --git a/tests/lib/client.auth.test.js b/tests/lib/client.auth.test.js
index a48eb78..41c0d92 100644
--- a/tests/lib/client.auth.test.js
+++ b/tests/lib/client.auth.test.js
@@ -1,13 +1,16 @@
 'use strict'
 
 var should = require('should'),
+    chance = new require('chance').Chance(),
     urljoin = require('url-join'),
+    util = require('util'),
     config = require('../../helpers').config,
     UsergridClient = require('../../lib/client'),
     UsergridEntity = require('../../lib/entity'),
     UsergridQuery = require('../../lib/query'),
     UsergridAuth = require('../../lib/auth'),
     UsergridAppAuth = require('../../lib/appAuth'),
+    UsergridUserAuth = require('../../lib/userAuth'),
     _ = require('lodash')
 
 _.mixin(require('lodash-uuid'))
@@ -31,6 +34,27 @@
         })
     })
 
+    it('should return a 200 ok', function() {
+        response.statusCode.should.equal(200)
+    })
+
+    it('should have a valid token', function() {
+        token.should.be.a.String()
+        token.length.should.be.greaterThan(10)
+    })
+
+    it('client.appAuth.token should be set to the token returned from Usergrid', function() {
+        client.appAuth.should.have.property('token').equal(token)
+    })
+
+    it('client.appAuth.isValid should be true', function() {
+        client.appAuth.should.have.property('isValid').which.is.true()
+    })
+
+    it('client.appAuth.expiry should be set to a future date', function() {
+        client.appAuth.should.have.property('expiry').greaterThan(Date.now())
+    })
+
     it('should fail when called without a clientId and clientSecret', function() {
         should(function() {
             var client = new UsergridClient()
@@ -47,6 +71,17 @@
         })
     })
 
+    it('should authenticate by passing a UsergridAppAuth instance with a custom ttl', function(done) {
+        var isolatedClient = new UsergridClient()
+        var ttlInMilliseconds = 500000
+        var appAuth = new UsergridAppAuth(config.clientId, config.clientSecret, ttlInMilliseconds)
+        isolatedClient.authenticateApp(appAuth, function(err, response, token) {
+            isolatedClient.appAuth.should.have.property('token').equal(token)
+            response.body.expires_in.should.equal(ttlInMilliseconds / 1000)
+            done()
+        })
+    })
+
     it('should not set client.appAuth when authenticating with a bad clientId and clientSecret in an object', function(done) {
         var failClient = new UsergridClient()
         failClient.authenticateApp({
@@ -92,27 +127,6 @@
             done()
         })
     })
-
-    it('should return a 200 ok', function() {
-        response.statusCode.should.equal(200)
-    })
-
-    it('should have a valid token', function() {
-        token.should.be.a.String()
-        token.length.should.be.greaterThan(10)
-    })
-
-    it('client.appAuth.token should be set to the token returned from Usergrid', function() {
-        client.appAuth.should.have.property('token').equal(token)
-    })
-
-    it('client.appAuth.isValid should be true', function() {
-        client.appAuth.should.have.property('isValid').which.is.true()
-    })
-
-    it('client.appAuth.expiry should be set to a future date', function() {
-        client.appAuth.should.have.property('expiry').greaterThan(Date.now())
-    })
 })
 
 describe('authenticateUser()', function() {
@@ -120,11 +134,12 @@
     this.slow(_slow)
     this.timeout(_timeout)
 
-    var response, token, client = new UsergridClient()
+    var response, token, email = util.format("%s@%s.com", chance.word(), chance.word()), client = new UsergridClient()
     before(function(done) {
         client.authenticateUser({
             username: config.test.username,
-            password: config.test.password
+            password: config.test.password,
+            email: email
         }, function(err, r, t) {
             response = r
             token = t
@@ -160,18 +175,27 @@
         client.currentUser.auth.should.have.property('expiry').greaterThan(Date.now())
     })
 
-    it('client.currentUser should have a username', function() {
+    it('client.currentUser should have a username and email', function() {
         client.currentUser.should.have.property('username')
-    })
-
-    it('client.currentUser should have an email', function() {
-        client.currentUser.should.have.property('email')
+        client.currentUser.should.have.property('email').equal(email)
     })
 
     it('client.currentUser and client.currentUser.auth should not store password', function() {
         client.currentUser.should.not.have.property('password')
         client.currentUser.auth.should.not.have.property('password')
     })
+
+    it('should support passing a UsergridUserAuth instance with a custom ttl', function(done) {
+        var newClient = new UsergridClient()
+        var ttlInMilliseconds = 500000        
+        var userAuth = new UsergridUserAuth(config.test.username, config.test.password, ttlInMilliseconds)
+        client.authenticateUser(userAuth, function(err, response, token) {
+            response.statusCode.should.equal(200)
+            client.currentUser.auth.token.should.equal(token)
+            response.body.expires_in.should.equal(ttlInMilliseconds / 1000)
+            done()
+        })
+    })
 })
 
 describe('appAuth, setAppAuth()', function() {
diff --git a/tests/lib/client.rest.test.js b/tests/lib/client.rest.test.js
index 8b0b0ce..ead846a 100644
--- a/tests/lib/client.rest.test.js
+++ b/tests/lib/client.rest.test.js
@@ -43,15 +43,15 @@
     })
 
     it('response.first should exist and have a valid uuid', function() {
-        response.first.should.be.an.Object().with.property('uuid').with.a.lengthOf(36)
+        response.first.should.be.an.instanceof(UsergridEntity).with.property('uuid').which.is.a.uuid()
     })
 
     it('response.entity should exist and have a valid uuid', function() {
-        response.entity.should.be.an.Object().with.property('uuid').with.a.lengthOf(36)
+        response.entity.should.be.an.instanceof(UsergridEntity).with.property('uuid').which.is.a.uuid()
     })
 
     it('response.last should exist and have a valid uuid', function() {
-        response.last.should.be.an.Object().with.property('uuid').with.a.lengthOf(36)
+        response.last.should.be.an.instanceof(UsergridEntity).with.property('uuid').which.is.a.uuid()
     })
 
     it('each entity should match the search criteria when passing a UsergridQuery object', function(done) {
@@ -102,7 +102,7 @@
     })
 
     it('response.entity should exist and have a valid uuid', function() {
-        response.entity.should.be.an.Object().with.property('uuid').with.a.lengthOf(36)
+        response.entity.should.be.an.instanceof(UsergridEntity).with.property('uuid').which.is.a.uuid()
     })
 
     it('response.entity.author should equal "Sir Arthur Conan Doyle"', function() {
@@ -251,7 +251,7 @@
 
         client.PUT(newEntity, function(err, usergridResponse) {
             usergridResponse.entity.should.be.an.Object()
-            usergridResponse.entity.should.have.property('uuid').with.a.lengthOf(36)
+            usergridResponse.entity.should.be.an.instanceof(UsergridEntity).with.property('uuid').which.is.a.uuid()
             usergridResponse.entity.should.have.property('author').equal('Frank Mills')
             usergridResponse.entity.created.should.equal(usergridResponse.entity.modified)
             done()
@@ -309,7 +309,7 @@
     it('should support updating a set of entities by passing an UsergridQuery object', function(done) {
 
         this.slow(_slow + 1000)
-        this.timeout(_timeout + 4000)
+        this.timeout(_timeout + 6000)
 
         var query = new UsergridQuery(config.test.collection).eq('cuisine', 'pizza').limit(2)
         var body = {
@@ -415,7 +415,7 @@
     it('should support deleting multiple entities by passing a UsergridQuery object', function(done) {
 
         this.slow(_slow + 1000)
-        this.timeout(_timeout + 4000)
+        this.timeout(_timeout + 6000)
 
         var entity = new UsergridEntity({
             type: config.test.collection,
diff --git a/tests/lib/entity.test.js b/tests/lib/entity.test.js
index 85d57f0..47aa8fb 100644
--- a/tests/lib/entity.test.js
+++ b/tests/lib/entity.test.js
@@ -8,8 +8,6 @@
     UsergridQuery = require('../../lib/query'),
     _ = require('lodash')
 
-_.mixin(require('lodash-uuid'))
-
 var _slow = 1500,
     _timeout = 4000
 
@@ -298,7 +296,7 @@
         })
     })
 
-    it('should refresh an entity with the latest server copy of itself using a UsergridClient instance argument', function(done) {
+    it('should refresh an entity with the latest server copy of itself by passing an instance of UsergridClient', function(done) {
         var client = new UsergridClient(config),
             now = Date.now()
         client.GET(config.test.collection, function(err, getResponse) {
@@ -334,7 +332,7 @@
         })
     })
 
-    it('should save an updated entity to the server using a UsergridClient instance argument', function(done) {
+    it('should save an updated entity to the server by passing an instance of UsergridClient', function(done) {
         var client = new UsergridClient(config),
             now = Date.now()
         client.GET(config.test.collection, function(err, getResponse) {
@@ -368,7 +366,7 @@
         })
     })
 
-    it('should remove an entity from the server using a UsergridClient instance argument', function(done) {
+    it('should remove an entity from the server by passing an instance of UsergridClient', function(done) {
         var client = new UsergridClient(config)
         client.POST(config.test.collection, {
             removeTest: 'test'
diff --git a/tests/lib/query.test.js b/tests/lib/query.test.js
index 446cb02..d9ecd41 100644
--- a/tests/lib/query.test.js
+++ b/tests/lib/query.test.js
@@ -21,12 +21,12 @@
 })
 
 describe('_limit', function() {
-    it('_limit should equal 2', function() {
+    it('_limit should equal 2 when setting .limit(2)', function() {
         var query = new UsergridQuery('cats').limit(2)
         query.should.have.property('_limit').equal(2)
     })
 
-    it('_limit should equal 10', function() {
+    it('_limit should equal 10 when setting .limit(10)', function() {
         var query = new UsergridQuery('cats').limit(10)
         query.should.have.property('_limit').equal(10)
     })
diff --git a/tests/lib/user.test.js b/tests/lib/user.test.js
new file mode 100644
index 0000000..8a853b6
--- /dev/null
+++ b/tests/lib/user.test.js
@@ -0,0 +1,144 @@
+'use strict'
+
+var should = require('should'),
+    util = require('util'),
+    chance = new require('chance').Chance(),
+    urljoin = require('url-join'),
+    config = require('../../helpers').config,
+    UsergridClient = require('../../lib/client'),
+    UsergridUser = require('../../lib/user'),
+    UsergridQuery = require('../../lib/query'),
+    _ = require('lodash')
+
+_.mixin(require('lodash-uuid'))
+
+var _slow = 1500,
+    _timeout = 4000,
+    _username1 = chance.word(),
+    _user1 = new UsergridUser({
+        username: _username1,
+        password: config.test.password
+    })
+
+before(function(done) {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    _user1.create(function(err, usergridResponse, user) {
+        done()
+    })
+})
+
+describe('create()', function() {
+
+    it(util.format("should create a new user with the username '%s'", _username1), function() {
+        _user1.username.should.equal(_username1)
+    })
+
+    it('should have a valid uuid', function() {
+        _user1.should.have.property('uuid').which.is.a.uuid()
+    })
+
+    it('should have a created date', function() {
+        _user1.should.have.property('created')
+    })
+
+    it('should be activated (i.e. has a valid password)', function() {
+        _user1.should.have.property('activated').true()
+    })
+
+    it('should not have a password property', function() {
+        _user1.should.not.have.property('password')
+    })
+
+    it('should fail gracefully when a username already exists', function(done) {
+        var user = new UsergridUser({
+            username: _username1,
+            password: config.test.password
+        })
+        user.create(function(err, usergridResponse) {
+            err.should.not.be.null()
+            err.should.containDeep({
+                name: 'duplicate_unique_property_exists'
+            })
+            usergridResponse.statusCode.should.be.greaterThanOrEqual(400)
+            done()
+        })
+    })
+
+    it('should create a new user on the server by passing an instance of UsergridClient', function(done) {
+        var client = new UsergridClient(config),
+            username = chance.word()
+        var user = new UsergridUser({
+            username: username,
+            password: config.test.password
+        })
+        user.create(client, function(err, usergridResponse, user) {
+            user.username.should.equal(username)
+            user.should.have.property('uuid').which.is.a.uuid()
+            user.should.have.property('created')
+            user.should.have.property('activated').true()
+            user.should.not.have.property('password')
+                // cleanup
+            user.remove(function(err, response) {
+                done()
+            })
+        })
+    })
+})
+
+describe('login()', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    it(util.format("it should log in the user '%s' and receive a token", _username1), function(done) {
+        _user1.password = config.test.password
+        _user1.login(function(err, response, token) {
+            _user1.auth.should.have.property('token').equal(token)
+            _user1.should.not.have.property('password')
+            _user1.auth.should.not.have.property('password')
+            done()
+        })
+    })
+})
+
+describe('logout()', function() {
+
+    this.slow(_slow)
+    this.timeout(_timeout)
+
+    it(util.format("it should log out '%s' and destroy the saved UsergridUserAuth instance", _username1), function(done) {
+        _user1.logout(function(err, response, success) {
+            response.statusCode.should.equal(200)
+            response.body.action.should.equal("revoked user token")
+            _user1.auth.isValid.should.be.false()
+            done()
+        })
+    })
+
+    it(util.format("it should log out all tokens for the user '%s' destroy the saved UsergridUserAuth instance", _username1), function(done) {
+        _user1.password = config.test.password
+        _user1.login(function(err, response, token) {
+            _user1.logoutAllSessions(function(err, response, success) {
+                response.statusCode.should.equal(200)
+                response.body.action.should.equal("revoked user tokens")
+                _user1.auth.isValid.should.be.false()
+                done()
+            })
+        })
+    })
+
+    it("it should return an error when attempting to log out a user that does not have a valid token", function(done) {
+        _user1.logout(function(err, response, success) {
+            err.should.containDeep({
+                    name: 'no_valid_token'
+                })
+                // cleanup
+            _user1.remove(function(err, response) {
+                done()
+            })
+        })
+    })
+})
\ No newline at end of file
diff --git a/tests/main.test.js b/tests/main.test.js
index aaf0412..7814a5c 100644
--- a/tests/main.test.js
+++ b/tests/main.test.js
@@ -1,5 +1,19 @@
 'use strict'
 
+// module config
+var should = require('should'),
+    _ = require('lodash')
+
+_.mixin(require('lodash-uuid'))
+
+should.Assertion.add('uuid', function() {
+    this.params = {
+        operator: 'to be a valid uuid'
+    };
+    this.assert(_.isUuid(this.obj));
+})
+// end module config
+
 describe('Usergrid', function() {
     return require('./lib/usergrid.test')
 })
@@ -38,4 +52,8 @@
 
 describe('UsergridEntity', function() {
     return require('./lib/entity.test')
+})
+
+describe('UsergridUser', function() {
+    return require('./lib/user.test')
 })
\ No newline at end of file