diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt
index a8d4cd4612634e5398d772d45bdd6e42ed178d35..9b9127f70acd87b87d02e4e85f6ec1eb7c58690e 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/server/AuthManager.kt
@@ -1,13 +1,22 @@
 package org.briarproject.mailbox.core.server
 
 import io.ktor.auth.Principal
+import org.briarproject.mailbox.core.api.Contact
 import org.briarproject.mailbox.core.db.Database
+import org.briarproject.mailbox.core.settings.SettingsManager
+import org.briarproject.mailbox.core.system.RandomIdManager
 import javax.inject.Inject
 import javax.inject.Singleton
 
+// We might want to move this somewhere else later
+internal const val SETTINGS_NAMESPACE_OWNER = "owner"
+internal const val SETTINGS_OWNER_TOKEN = "ownerToken"
+
 @Singleton
 class AuthManager @Inject constructor(
     private val db: Database,
+    private val settingsManager: SettingsManager,
+    private val randomIdManager: RandomIdManager,
 ) {
 
     /**
@@ -15,29 +24,51 @@ class AuthManager @Inject constructor(
      * or null if this token doesn't belong to any principal.
      */
     fun getPrincipal(token: String): MailboxPrincipal? {
-        // TODO get real principal owning token from DB or null of token unknown
-        return MailboxPrincipal.Owner(token)
+        randomIdManager.assertIsRandomId(token)
+        return db.transactionWithResult(true) { txn ->
+            val contact = db.getContactWithToken(txn, token)
+            if (contact != null) {
+                MailboxPrincipal.ContactPrincipal(contact)
+            } else {
+                val settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER)
+                if (token == settings[SETTINGS_OWNER_TOKEN]) MailboxPrincipal.Owner
+                else null
+            }
+        }
     }
 
     /**
      * @throws [AuthenticationException] when given [principal] is NOT allowed
-     * to download or delete from the given [folderId].
+     * to download or delete from the given [folderId] which is assumed to be validated already.
      */
     @Throws(AuthenticationException::class)
     fun assertCanDownloadFromFolder(principal: MailboxPrincipal?, folderId: String) {
         if (principal == null) throw AuthenticationException()
 
-        // TODO check access of principal to folderId
+        if (principal is MailboxPrincipal.Owner) {
+            val contacts = db.transactionWithResult(true) { txn -> db.getContacts(txn) }
+            val noOutboxFound = contacts.none { c -> folderId == c.outboxId }
+            if (noOutboxFound) throw AuthenticationException()
+        } else if (principal is MailboxPrincipal.ContactPrincipal) {
+            if (folderId != principal.contact.inboxId) throw AuthenticationException()
+        }
     }
 
     /**
      * @throws [AuthenticationException] when given [principal] is NOT allowed
-     * to post to the given [folderId].
+     * to post to the given [folderId] which is assumed to be validated already.
      */
     @Throws(AuthenticationException::class)
     fun assertCanPostToFolder(principal: MailboxPrincipal?, folderId: String) {
         if (principal == null) throw AuthenticationException()
-        // TODO check access of principal to folderId
+
+        if (principal is MailboxPrincipal.Owner) {
+            val contacts = db.transactionWithResult(true) { txn -> db.getContacts(txn) }
+            val noInboxFound = contacts.none { c -> folderId == c.inboxId }
+            if (noInboxFound) throw AuthenticationException()
+        } else if (principal is MailboxPrincipal.ContactPrincipal) {
+            if (folderId != principal.contact.outboxId) throw AuthenticationException()
+        }
     }
 
     /**
@@ -50,11 +81,9 @@ class AuthManager @Inject constructor(
 
 }
 
-sealed class MailboxPrincipal(val token: String) : Principal {
-
-    class Owner(token: String) : MailboxPrincipal(token)
-    class Contact(token: String, val contactId: Int) : MailboxPrincipal(token)
-
+sealed class MailboxPrincipal : Principal {
+    object Owner : MailboxPrincipal()
+    class ContactPrincipal(val contact: Contact) : MailboxPrincipal()
 }
 
 class AuthenticationException : IllegalStateException()
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
index 20b9590c42713f4fc9ec144fbc436cdd995ec4db..b269d9dcb7d5e8e5649615da87c6a61dca813134 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
@@ -32,7 +32,7 @@ internal class TestModule(private val tempDir: File) {
     @Provides
     fun provideDatabaseConfig() = object : DatabaseConfig {
         override fun getDatabaseDirectory(): File {
-            return tempDir
+            return File(tempDir, "db")
         }
     }
 }
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..546e5ce16d0328a75371b8ad252e02d1dc543c55
--- /dev/null
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/AuthManagerTest.kt
@@ -0,0 +1,5 @@
+package org.briarproject.mailbox.core.server
+
+class AuthManagerTest {
+    // TODO write unit tests
+}