diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go
index 550bba9a8..4e8c5a570 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go
@@ -20,30 +20,16 @@ import (
 	"net/http"
 	"strings"
 
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
 	"github.com/matrix-org/util"
 )
 
-// VerifyAccessToken TODO: Remove me.
-func VerifyAccessToken(req *http.Request) (userID string, resErr *util.JSONResponse) {
-	token, err := extractAccessToken(req)
-	if err != nil {
-		resErr = &util.JSONResponse{
-			Code: 401,
-			JSON: jsonerror.MissingToken(err.Error()),
-		}
-		return
-	}
-	userID = token
-	return
-}
-
-// VerifyAccessTokenNew verifies that an access token was supplied in the given HTTP request
+// VerifyAccessToken verifies that an access token was supplied in the given HTTP request
 // and returns the device it corresponds to. Returns resErr (an error response which can be
 // sent to the client) if the token is invalid or there was a problem querying the database.
-func VerifyAccessTokenNew(req *http.Request, deviceDB *devices.Database) (device *types.Device, resErr *util.JSONResponse) {
+func VerifyAccessToken(req *http.Request, deviceDB *devices.Database) (device *authtypes.Device, resErr *util.JSONResponse) {
 	token, err := extractAccessToken(req)
 	if err != nil {
 		resErr = &util.JSONResponse{
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go
similarity index 98%
rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go
rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go
index 21b10e038..ed33d0b5e 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package types
+package authtypes
 
 import (
 	"github.com/matrix-org/gomatrixserverlib"
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go
similarity index 97%
rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go
rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go
index 72352cdee..4feceada0 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package types
+package authtypes
 
 // Device represents a client's device (mobile, web, etc)
 type Device struct {
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go
similarity index 92%
rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go
rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go
index 42cb477af..6a90b295f 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go
@@ -1,4 +1,4 @@
-package types
+package authtypes
 
 // LoginType are specified by http://matrix.org/docs/spec/client_server/r0.2.0.html#login-types
 type LoginType string
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go
index dc5b51965..ad34a4004 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go
@@ -19,7 +19,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/gomatrixserverlib"
 )
 
@@ -76,10 +76,10 @@ func (s *accountsStatements) prepare(db *sql.DB, server gomatrixserverlib.Server
 // insertAccount creates a new account. 'hash' should be the password hash for this account. If it is missing,
 // this account will be passwordless. Returns an error if this account already exists. Returns the account
 // on success.
-func (s *accountsStatements) insertAccount(localpart, hash string) (acc *types.Account, err error) {
+func (s *accountsStatements) insertAccount(localpart, hash string) (acc *authtypes.Account, err error) {
 	createdTimeMS := time.Now().UnixNano() / 1000000
 	if _, err = s.insertAccountStmt.Exec(localpart, createdTimeMS, hash); err == nil {
-		acc = &types.Account{
+		acc = &authtypes.Account{
 			Localpart:  localpart,
 			UserID:     makeUserID(localpart, s.serverName),
 			ServerName: s.serverName,
@@ -93,8 +93,8 @@ func (s *accountsStatements) selectPasswordHash(localpart string) (hash string,
 	return
 }
 
-func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*types.Account, error) {
-	var acc types.Account
+func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*authtypes.Account, error) {
+	var acc authtypes.Account
 	err := s.selectAccountByLocalpartStmt.QueryRow(localpart).Scan(&acc.Localpart)
 	if err != nil {
 		acc.UserID = makeUserID(localpart, s.serverName)
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go
index bb08870cf..5dbd49439 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go
@@ -16,7 +16,7 @@ package accounts
 
 import (
 	"database/sql"
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/gomatrixserverlib"
 	"golang.org/x/crypto/bcrypt"
 	// Import the postgres database driver.
@@ -45,7 +45,7 @@ func NewDatabase(dataSourceName string, serverName gomatrixserverlib.ServerName)
 
 // GetAccountByPassword returns the account associated with the given localpart and password.
 // Returns sql.ErrNoRows if no account exists which matches the given credentials.
-func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*types.Account, error) {
+func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*authtypes.Account, error) {
 	hash, err := d.accounts.selectPasswordHash(localpart)
 	if err != nil {
 		return nil, err
@@ -58,7 +58,7 @@ func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*t
 
 // CreateAccount makes a new account with the given login name and password. If no password is supplied,
 // the account will be a passwordless account.
-func (d *Database) CreateAccount(localpart, plaintextPassword string) (*types.Account, error) {
+func (d *Database) CreateAccount(localpart, plaintextPassword string) (*authtypes.Account, error) {
 	hash, err := hashPassword(plaintextPassword)
 	if err != nil {
 		return nil, err
diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go
index 9c2ae04ff..ef5fe495d 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go
@@ -15,7 +15,7 @@
 package devices
 
 import (
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 )
 
 // Database represents a device database.
@@ -24,14 +24,14 @@ type Database struct {
 }
 
 // NewDatabase creates a new device database
-func NewDatabase() *Database {
-	return &Database{}
+func NewDatabase(dataSource string) (*Database, error) {
+	return &Database{}, nil
 }
 
 // GetDeviceByAccessToken returns the device matching the given access token.
-func (d *Database) GetDeviceByAccessToken(token string) (*types.Device, error) {
+func (d *Database) GetDeviceByAccessToken(token string) (*authtypes.Device, error) {
 	// TODO: Actual implementation
-	return &types.Device{
+	return &authtypes.Device{
 		UserID: token,
 	}, nil
 }
diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go b/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go
index 42bfcc00a..a7d47c495 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go
@@ -19,14 +19,14 @@ import (
 	"net/http"
 
 	"github.com/gorilla/mux"
-	"github.com/matrix-org/dendrite/clientapi/auth"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
 	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
 	"github.com/matrix-org/dendrite/clientapi/config"
 	"github.com/matrix-org/dendrite/clientapi/producers"
 	"github.com/matrix-org/dendrite/clientapi/readers"
 	"github.com/matrix-org/dendrite/clientapi/writers"
+	"github.com/matrix-org/dendrite/common"
 	"github.com/matrix-org/dendrite/roomserver/api"
 	"github.com/matrix-org/util"
 	"github.com/prometheus/client_golang/prometheus"
@@ -36,49 +36,50 @@ const pathPrefixR0 = "/_matrix/client/r0"
 
 // Setup registers HTTP handlers with the given ServeMux. It also supplies the given http.Client
 // to clients which need to make outbound HTTP requests.
-func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI, producer *producers.RoomserverProducer, queryAPI api.RoomserverQueryAPI, accountDB *accounts.Database) {
+func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI, producer *producers.RoomserverProducer,
+	queryAPI api.RoomserverQueryAPI, accountDB *accounts.Database, deviceDB *devices.Database) {
 	apiMux := mux.NewRouter()
 	r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
 	r0mux.Handle("/createRoom",
-		makeAPI("createRoom", func(req *http.Request) util.JSONResponse {
-			return writers.CreateRoom(req, cfg, producer)
+		common.MakeAuthAPI("createRoom", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
+			return writers.CreateRoom(req, device, cfg, producer)
 		}),
 	)
 	r0mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}",
-		makeAPI("send_message", func(req *http.Request) util.JSONResponse {
+		common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
 			vars := mux.Vars(req)
-			return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], nil, cfg, queryAPI, producer)
+			return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], nil, cfg, queryAPI, producer)
 		}),
 	)
 	r0mux.Handle("/rooms/{roomID}/state/{eventType}",
-		makeAPI("send_message", func(req *http.Request) util.JSONResponse {
+		common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
 			vars := mux.Vars(req)
 			emptyString := ""
-			return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], &emptyString, cfg, queryAPI, producer)
+			return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], &emptyString, cfg, queryAPI, producer)
 		}),
 	)
 	r0mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}",
-		makeAPI("send_message", func(req *http.Request) util.JSONResponse {
+		common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
 			vars := mux.Vars(req)
 			stateKey := vars["stateKey"]
-			return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], &stateKey, cfg, queryAPI, producer)
+			return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], &stateKey, cfg, queryAPI, producer)
 		}),
 	)
 
-	r0mux.Handle("/register", makeAPI("register", func(req *http.Request) util.JSONResponse {
+	r0mux.Handle("/register", common.MakeAPI("register", func(req *http.Request) util.JSONResponse {
 		return writers.Register(req, accountDB)
 	}))
 
 	// Stub endpoints required by Riot
 
 	r0mux.Handle("/login",
-		makeAPI("login", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("login", func(req *http.Request) util.JSONResponse {
 			return readers.Login(req, cfg)
 		}),
 	)
 
 	r0mux.Handle("/pushrules/",
-		makeAPI("push_rules", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("push_rules", func(req *http.Request) util.JSONResponse {
 			// TODO: Implement push rules API
 			res := json.RawMessage(`{
 					"global": {
@@ -97,7 +98,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 	)
 
 	r0mux.Handle("/user/{userID}/filter",
-		makeAPI("make_filter", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("make_filter", func(req *http.Request) util.JSONResponse {
 			// TODO: Persist filter and return filter ID
 			return util.JSONResponse{
 				Code: 200,
@@ -107,7 +108,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 	)
 
 	r0mux.Handle("/user/{userID}/filter/{filterID}",
-		makeAPI("filter", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("filter", func(req *http.Request) util.JSONResponse {
 			// TODO: Retrieve filter based on ID
 			return util.JSONResponse{
 				Code: 200,
@@ -119,7 +120,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 	// Riot user settings
 
 	r0mux.Handle("/profile/{userID}",
-		makeAPI("profile", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("profile", func(req *http.Request) util.JSONResponse {
 			// TODO: Get profile data for user ID
 			return util.JSONResponse{
 				Code: 200,
@@ -129,7 +130,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 	)
 
 	r0mux.Handle("/account/3pid",
-		makeAPI("account_3pid", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("account_3pid", func(req *http.Request) util.JSONResponse {
 			// TODO: Get 3pid data for user ID
 			res := json.RawMessage(`{"threepids":[]}`)
 			return util.JSONResponse{
@@ -141,7 +142,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 
 	// Riot logs get flooded unless this is handled
 	r0mux.Handle("/presence/{userID}/status",
-		makeAPI("presence", func(req *http.Request) util.JSONResponse {
+		common.MakeAPI("presence", func(req *http.Request) util.JSONResponse {
 			// TODO: Set presence (probably the responsibility of a presence server not clientapi)
 			return util.JSONResponse{
 				Code: 200,
@@ -153,21 +154,3 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
 	servMux.Handle("/metrics", prometheus.Handler())
 	servMux.Handle("/api/", http.StripPrefix("/api", apiMux))
 }
-
-// make a util.JSONRequestHandler function into an http.Handler which checks the access token in the request.
-func makeAuthAPI(metricsName string, deviceDB *devices.Database, f func(*http.Request, types.Device) util.JSONResponse) http.Handler {
-	h := util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse {
-		device, resErr := auth.VerifyAccessTokenNew(req, deviceDB)
-		if resErr != nil {
-			return *resErr
-		}
-		return f(req, *device)
-	})
-	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
-}
-
-// make a util.JSONRequestHandler function into an http.Handler.
-func makeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler {
-	h := util.NewJSONRequestHandler(f)
-	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
-}
diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go
index e14c56fb5..a25017001 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go
@@ -22,7 +22,7 @@ import (
 	"time"
 
 	log "github.com/Sirupsen/logrus"
-	"github.com/matrix-org/dendrite/clientapi/auth"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/config"
 	"github.com/matrix-org/dendrite/clientapi/events"
 	"github.com/matrix-org/dendrite/clientapi/httputil"
@@ -91,22 +91,19 @@ type fledglingEvent struct {
 }
 
 // CreateRoom implements /createRoom
-func CreateRoom(req *http.Request, cfg config.ClientAPI, producer *producers.RoomserverProducer) util.JSONResponse {
+func CreateRoom(req *http.Request, device *authtypes.Device, cfg config.ClientAPI, producer *producers.RoomserverProducer) util.JSONResponse {
 	// TODO: Check room ID doesn't clash with an existing one, and we
 	//       probably shouldn't be using pseudo-random strings, maybe GUIDs?
 	roomID := fmt.Sprintf("!%s:%s", util.RandomString(16), cfg.ServerName)
-	return createRoom(req, cfg, roomID, producer)
+	return createRoom(req, device, cfg, roomID, producer)
 }
 
 // createRoom implements /createRoom
-func createRoom(req *http.Request, cfg config.ClientAPI, roomID string, producer *producers.RoomserverProducer) util.JSONResponse {
+func createRoom(req *http.Request, device *authtypes.Device, cfg config.ClientAPI, roomID string, producer *producers.RoomserverProducer) util.JSONResponse {
 	logger := util.GetLogger(req.Context())
-	userID, resErr := auth.VerifyAccessToken(req)
-	if resErr != nil {
-		return *resErr
-	}
+	userID := device.UserID
 	var r createRoomRequest
-	resErr = httputil.UnmarshalJSONRequest(req, &r)
+	resErr := httputil.UnmarshalJSONRequest(req, &r)
 	if resErr != nil {
 		return *resErr
 	}
diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/register.go b/src/github.com/matrix-org/dendrite/clientapi/writers/register.go
index 753fb1a0e..5191a7195 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/writers/register.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/writers/register.go
@@ -5,8 +5,8 @@ import (
 	"net/http"
 
 	log "github.com/Sirupsen/logrus"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
-	"github.com/matrix-org/dendrite/clientapi/auth/types"
 	"github.com/matrix-org/dendrite/clientapi/httputil"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
 	"github.com/matrix-org/gomatrixserverlib"
@@ -34,15 +34,15 @@ type registerRequest struct {
 }
 
 type authDict struct {
-	Type    types.LoginType `json:"type"`
-	Session string          `json:"session"`
+	Type    authtypes.LoginType `json:"type"`
+	Session string              `json:"session"`
 	// TODO: Lots of custom keys depending on the type
 }
 
 // http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
 type userInteractiveResponse struct {
 	Flows     []authFlow             `json:"flows"`
-	Completed []types.LoginType      `json:"completed"`
+	Completed []authtypes.LoginType  `json:"completed"`
 	Params    map[string]interface{} `json:"params"`
 	Session   string                 `json:"session"`
 }
@@ -50,12 +50,12 @@ type userInteractiveResponse struct {
 // authFlow represents one possible way that the client can authenticate a request.
 // http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
 type authFlow struct {
-	Stages []types.LoginType `json:"stages"`
+	Stages []authtypes.LoginType `json:"stages"`
 }
 
 func newUserInteractiveResponse(sessionID string, fs []authFlow) userInteractiveResponse {
 	return userInteractiveResponse{
-		fs, []types.LoginType{}, make(map[string]interface{}), sessionID,
+		fs, []authtypes.LoginType{}, make(map[string]interface{}), sessionID,
 	}
 }
 
@@ -119,7 +119,7 @@ func Register(req *http.Request, accountDB *accounts.Database) util.JSONResponse
 			// TODO: Hard-coded 'dummy' auth for now with a bogus session ID.
 			//       Server admins should be able to change things around (eg enable captcha)
 			JSON: newUserInteractiveResponse("totallyuniquesessionid", []authFlow{
-				{[]types.LoginType{types.LoginTypeDummy}},
+				{[]authtypes.LoginType{authtypes.LoginTypeDummy}},
 			}),
 		}
 	}
@@ -129,7 +129,7 @@ func Register(req *http.Request, accountDB *accounts.Database) util.JSONResponse
 
 	// TODO: email / msisdn / recaptcha auth types.
 	switch r.Auth.Type {
-	case types.LoginTypeDummy:
+	case authtypes.LoginTypeDummy:
 		// there is nothing to do
 		return completeRegistration(accountDB, r.Username, r.Password)
 	default:
diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go b/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go
index e4cd3e0df..ec65fadb6 100644
--- a/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go
+++ b/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/matrix-org/dendrite/clientapi/auth"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/config"
 	"github.com/matrix-org/dendrite/clientapi/httputil"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
@@ -39,14 +39,11 @@ type sendEventResponse struct {
 // SendEvent implements:
 //   /rooms/{roomID}/send/{eventType}/{txnID}
 //   /rooms/{roomID}/state/{eventType}/{stateKey}
-func SendEvent(req *http.Request, roomID, eventType, txnID string, stateKey *string, cfg config.ClientAPI, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer) util.JSONResponse {
+func SendEvent(req *http.Request, device *authtypes.Device, roomID, eventType, txnID string, stateKey *string, cfg config.ClientAPI, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer) util.JSONResponse {
 	// parse the incoming http request
-	userID, resErr := auth.VerifyAccessToken(req)
-	if resErr != nil {
-		return *resErr
-	}
+	userID := device.UserID
 	var r map[string]interface{} // must be a JSON object
-	resErr = httputil.UnmarshalJSONRequest(req, &r)
+	resErr := httputil.UnmarshalJSONRequest(req, &r)
 	if resErr != nil {
 		return *resErr
 	}
diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go
index a2b9c31df..c75ca3235 100644
--- a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go
+++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go
@@ -20,6 +20,7 @@ import (
 	"strings"
 
 	"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
+	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
 	"github.com/matrix-org/dendrite/clientapi/config"
 	"github.com/matrix-org/dendrite/clientapi/producers"
 	"github.com/matrix-org/dendrite/clientapi/routing"
@@ -85,7 +86,11 @@ func main() {
 	if err != nil {
 		log.Panicf("Failed to setup account database(%s): %s", accountDataSource, err.Error())
 	}
+	deviceDB, err := devices.NewDatabase(accountDataSource)
+	if err != nil {
+		log.Panicf("Failed to setup device database(%s): %s", accountDataSource, err.Error())
+	}
 
-	routing.Setup(http.DefaultServeMux, http.DefaultClient, cfg, roomserverProducer, queryAPI, accountDB)
+	routing.Setup(http.DefaultServeMux, http.DefaultClient, cfg, roomserverProducer, queryAPI, accountDB, deviceDB)
 	log.Fatal(http.ListenAndServe(bindAddr, nil))
 }
diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go
index 5d1bf8e2e..01e12f040 100644
--- a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go
+++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go
@@ -20,6 +20,7 @@ import (
 	"net/http"
 	"os"
 
+	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
 	"github.com/matrix-org/dendrite/common"
 	"github.com/matrix-org/dendrite/syncapi/config"
 	"github.com/matrix-org/dendrite/syncapi/consumers"
@@ -72,6 +73,12 @@ func main() {
 		log.Panicf("startup: failed to create sync server database with data source %s : %s", cfg.DataSource, err)
 	}
 
+	// TODO: DO NOT USE THIS DATABASE
+	deviceDB, err := devices.NewDatabase(cfg.DataSource)
+	if err != nil {
+		log.Panicf("startup: failed to create device database with data source %s : %s", cfg.DataSource, err)
+	}
+
 	pos, err := db.SyncStreamPosition()
 	if err != nil {
 		log.Panicf("startup: failed to get latest sync stream position : %s", err)
@@ -90,6 +97,6 @@ func main() {
 	}
 
 	log.Info("Starting sync server on ", *bindAddr)
-	routing.SetupSyncServerListeners(http.DefaultServeMux, http.DefaultClient, *cfg, sync.NewRequestPool(db, n))
+	routing.SetupSyncServerListeners(http.DefaultServeMux, http.DefaultClient, *cfg, sync.NewRequestPool(db, n), deviceDB)
 	log.Fatal(http.ListenAndServe(*bindAddr, nil))
 }
diff --git a/src/github.com/matrix-org/dendrite/common/httpapi.go b/src/github.com/matrix-org/dendrite/common/httpapi.go
new file mode 100644
index 000000000..0ab33925f
--- /dev/null
+++ b/src/github.com/matrix-org/dendrite/common/httpapi.go
@@ -0,0 +1,28 @@
+package common
+
+import (
+	"github.com/matrix-org/dendrite/clientapi/auth"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
+	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
+	"github.com/matrix-org/util"
+	"github.com/prometheus/client_golang/prometheus"
+	"net/http"
+)
+
+// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which checks the access token in the request.
+func MakeAuthAPI(metricsName string, deviceDB *devices.Database, f func(*http.Request, *authtypes.Device) util.JSONResponse) http.Handler {
+	h := util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse {
+		device, resErr := auth.VerifyAccessToken(req, deviceDB)
+		if resErr != nil {
+			return *resErr
+		}
+		return f(req, device)
+	})
+	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
+}
+
+// MakeAPI turns a util.JSONRequestHandler function into an http.Handler.
+func MakeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler {
+	h := util.NewJSONRequestHandler(f)
+	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
+}
diff --git a/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go
index 7c7be9836..ad09cd172 100644
--- a/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go
+++ b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go
@@ -18,6 +18,9 @@ import (
 	"net/http"
 
 	"github.com/gorilla/mux"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
+	"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
+	"github.com/matrix-org/dendrite/common"
 	"github.com/matrix-org/dendrite/syncapi/config"
 	"github.com/matrix-org/dendrite/syncapi/sync"
 	"github.com/matrix-org/util"
@@ -27,17 +30,12 @@ import (
 const pathPrefixR0 = "/_matrix/client/r0"
 
 // SetupSyncServerListeners configures the given mux with sync-server listeners
-func SetupSyncServerListeners(servMux *http.ServeMux, httpClient *http.Client, cfg config.Sync, srp *sync.RequestPool) {
+func SetupSyncServerListeners(servMux *http.ServeMux, httpClient *http.Client, cfg config.Sync, srp *sync.RequestPool, deviceDB *devices.Database) {
 	apiMux := mux.NewRouter()
 	r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
-	r0mux.Handle("/sync", make("sync", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse {
-		return srp.OnIncomingSyncRequest(req)
-	})))
+	r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
+		return srp.OnIncomingSyncRequest(req, device)
+	}))
 	servMux.Handle("/metrics", prometheus.Handler())
 	servMux.Handle("/api/", http.StripPrefix("/api", apiMux))
 }
-
-// make a util.JSONRequestHandler into an http.Handler
-func make(metricsName string, h util.JSONRequestHandler) http.Handler {
-	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
-}
diff --git a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go
index 8e9affb68..08bad334a 100644
--- a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go
+++ b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go
@@ -19,7 +19,7 @@ import (
 	"time"
 
 	log "github.com/Sirupsen/logrus"
-	"github.com/matrix-org/dendrite/clientapi/auth"
+	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
 	"github.com/matrix-org/dendrite/clientapi/httputil"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
 	"github.com/matrix-org/dendrite/syncapi/storage"
@@ -41,13 +41,10 @@ func NewRequestPool(db *storage.SyncServerDatabase, n *Notifier) *RequestPool {
 // OnIncomingSyncRequest is called when a client makes a /sync request. This function MUST be
 // called in a dedicated goroutine for this request. This function will block the goroutine
 // until a response is ready, or it times out.
-func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request) util.JSONResponse {
+func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *authtypes.Device) util.JSONResponse {
 	// Extract values from request
 	logger := util.GetLogger(req.Context())
-	userID, resErr := auth.VerifyAccessToken(req)
-	if resErr != nil {
-		return *resErr
-	}
+	userID := device.UserID
 	syncReq, err := newSyncRequest(req, userID)
 	if err != nil {
 		return util.JSONResponse{