             version = new Buffer(4)
             version.writeUInt32LE(protoVersion, 0)
 
-            # Since the auth key has a variable length, we need to
-            # both encode its length in the wire format (little endian
-            # 32 bit), and the bytes themselves.
-            auth_buffer = new Buffer(@authKey, 'ascii')
-            auth_length = new Buffer(4)
-            auth_length.writeUInt32LE(auth_buffer.length, 0)
-
             # Send the protocol type that we will be using to
             # communicate with the server. Json is the only currently
             # supported protocol.
             protocol = new Buffer(4)
             protocol.writeUInt32LE(protoProtocol, 0)
 
-            # Write the version, auth key length, auth key, and
-            # protocol number to the socket, in that order.
-            @rawSocket.write Buffer.concat([version, auth_length, auth_buffer, protocol])
+            r_string = new Buffer(crypto.randomBytes(18)).toString('base64')
+
+            @rawSocket.username = host["username"]
+            @rawSocket.password = host["password"]
+
+            # Default to admin user with no password if none is given.
+            if @rawSocket.username is undefined
+                @rawSocket.username = "admin"
+            if @rawSocket.password is undefined
+                @rawSocket.password = ""
+
+            client_first_message_bare = "n=" + @rawSocket.username + ",r=" + r_string
+
+            message = JSON.stringify({
+                protocol_version: protoVersionNumber,
+                authentication_method: "SCRAM-SHA-256",
+                authentication: "n,," + client_first_message_bare})
+
+            nullbyte = new Buffer('\0', "binary")
+
+            @rawSocket.write Buffer.concat([version, Buffer(message.toString()), nullbyte])
 
             # Now we have to wait for a response from the server
             # acknowledging the new connection. The following callback
             # will be invoked when the server sends the first few
             # bytes over the socket.
+
+            state = 1
+            min = 0
+            max = 0
+            server_first_message = ""
+            server_signature = ""
+            auth_r = ""
+            auth_salt = ""
+            auth_i = 0
+
+            xor_bytes = (a, b) ->
+                res = []
+                len = Math.min(a.length, b.length)
+                for i in [0...len]
+                    res.push(a[i] ^ b[i])
+                return new Buffer(res)
+
+            compare_digest = (a, b) ->
+                left = undefined
+                right = b
+                result = undefined
+                if a.length is b.length
+                    left = a
+                    result = 0
+                else
+                    left = b
+                    result = 1
+
+                len = Math.min(a.length, b.length)
+                for i in [0...len]
+                    result |= xor_bytes(a[i],b[i])
+
+                return result is 0
+
+            handshake_error = (code, message) =>
+                if 10 <= code <= 20
+                    throw new err.ReqlAuthError(message)
+                else
+                    throw new err.ReqlDriverError(message)
+
             handshake_callback = (buf) =>
                 # Once we receive a response, extend the current
                 # buffer with the data from the server. The reason we


        # Once the TCP socket successfully connects, we can begin the
        # handshake with the server to establish the connection on the
        # server. This is where we decide what protocol to use, and
        # send things like the authKey etc.
        @rawSocket.once 'connect', =>

            # The protocol specifies that the magic number for the
            # version should be given as a little endian 32 bit
            # unsigned integer. The value is given in the `proto-def`

                # response, and only disable this event listener at
                # that time.
                @buffer = Buffer.concat([@buffer, buf])
                # Next we read bytes until we get a null byte. Then we follow
                # the new handshake logic to authenticate the user with the
                # server.

                j = 0
                for b,i in @buffer
                    if b is 0
                        # Here we pull the status string out of the
                        # buffer and convert it into a string.
                        status_buf = @buffer.slice(j, i)
                        j = i+1
                        status_str = status_buf.toString()
                        # Get the reply from the server, and parse it as JSON
                        server_reply = JSON.parse(status_str)

                        if state is 1
                            if not server_reply.success
                                handshake_error(server_reply.error_code, server_reply.error)
                            min = server_reply.min_protocol_version
                            max = server_reply.max_protocol_version

                            if min > protoVersionNumber or max < protoVersionNumber
                                # We don't actually support changing the protocol yet, so just error.
                                throw new err.ReqlDriverError(
                                    """Unsupported protocol version #{protoVersionNumber}, \
                                    expected between #{min} and #{max}.""")
                            state = 2
                        else if state is 2
                            if not server_reply.success
                                handshake_error(server_reply.error_code, server_reply.error)

                            authentication = {}
                            server_first_message = server_reply.authentication

                            for item in server_first_message.split(",")
                                i = item.indexOf("=")
                                authentication[item.slice(0, i)] = item.slice(i+1)
                            auth_r = authentication.r
                            auth_salt = new Buffer(authentication.s, 'base64')
                            auth_i = parseInt(authentication.i)

                            if not auth_r.substr(0, r_string) == r_string
                                throw new err.ReqlAuthError("Invalid nonce from server")

                            client_final_message_without_proof = "c=biws,r=" + auth_r

                            salted_password = crypto.pbkdf2Sync(@rawSocket.password, auth_salt, auth_i, 32, "sha256")
                            client_key = crypto.createHmac("sha256", salted_password).update("Client Key").digest()
                            stored_key = crypto.createHash("sha256").update(client_key).digest()

                            auth_message =
                                client_first_message_bare + "," +
                                server_first_message + "," +
                                client_final_message_without_proof

                            client_signature = crypto.createHmac("sha256", stored_key).update(auth_message).digest()
                            client_proof = xor_bytes(client_key, client_signature)

                            server_key = crypto.createHmac("sha256", salted_password).update("Server Key").digest()
                            server_signature = crypto.createHmac("sha256", server_key).update(auth_message).digest()

                            state = 3

                            message = JSON.stringify({authentication: client_final_message_without_proof + ",p=" + client_proof.toString("base64")})

                            nullbyte = new Buffer('\0', "binary")

                            @rawSocket.write Buffer.concat([Buffer(message.toString()), nullbyte])
                        else if state is 3
                            if not server_reply.success
                                handshake_error(server_reply.error_code, server_reply.error)

                            first_equals = server_reply.authentication.indexOf('=')
                            v = server_reply.authentication.slice(first_equals+1)

                            if not compare_digest(v, server_signature.toString("base64"))
                                throw new err.ReqlAuthError("Invalid server signature")

                            state = 4
                            @rawSocket.removeListener('data', handshake_callback)
                            @rawSocket.on 'data', (buf) => @_data(buf)

                            # We also want to cancel the timeout error
                            # callback that we set earlier. Even though we
                            # haven't checked `status_str` yet, we've
                            # gotten a response so it isn't a timeout.
                            clearTimeout(timeout)

                            # Notify listeners we've connected
                            # successfully. Notably, the Connection
