diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go
index 71eae7b11ac30335a48835f9b3c49f07cc07b56b..424d3f830174445334a48de0ced69eaa5424f191 100644
--- a/api/authenticatedChannel.go
+++ b/api/authenticatedChannel.go
@@ -4,6 +4,7 @@ import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
+	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/contact"
 	"gitlab.com/elixxir/client/storage/e2e"
 	"gitlab.com/xx_network/primitives/id"
@@ -30,26 +31,12 @@ func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact,
 		c.storage, c.network)
 }
 
-// RegisterAuthCallbacks registers both callbacks for authenticated channels.
-// This can only be called once
-func (c *Client) RegisterAuthCallbacks(request auth.RequestCallback,
-	confirm auth.ConfirmCallback) error {
-	jww.INFO.Printf("RegisterAuthCallbacks(...)")
+// GetAuthRegistrar gets the object which allows the registration of auth
+// callbacks
+func (c *Client) GetAuthRegistrar() interfaces.Auth {
+	jww.INFO.Printf("GetAuthRegistrar(...)")
 
-	exicuted := false
-
-	c.authOnce.Do(func() {
-		stop := auth.RegisterCallbacks(request, confirm, c.switchboard,
-			c.storage, c.network)
-		c.runner.Add(stop)
-		exicuted = true
-	})
-
-	if !exicuted {
-		return errors.New("Cannot register auth callbacks more than " +
-			"once")
-	}
-	return nil
+	return c.auth
 }
 
 // GetAuthenticatedChannelRequest returns the contact received in a request if
diff --git a/api/client.go b/api/client.go
index c2580f87058d44488539c9b14aa7c35fe436babf..e9c7e5cb693e7486783f3c3f20fba3442cbe24e6 100644
--- a/api/client.go
+++ b/api/client.go
@@ -9,6 +9,7 @@ package api
 import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/auth"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/interfaces/user"
@@ -25,7 +26,6 @@ import (
 	"gitlab.com/elixxir/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/ndf"
-	"sync"
 	"time"
 )
 
@@ -46,14 +46,12 @@ type Client struct {
 	network interfaces.NetworkManager
 	//object used to register and communicate with permissioning
 	permissioning *permissioning.Permissioning
+	//object containing auth interactions
+	auth *auth.Manager
 
 	//contains stopables for all running threads
 	runner *stoppable.Multi
 	status *statusTracker
-
-	// contains the sync once used to ensure authenticated channel callbacks are
-	// only registered once
-	authOnce sync.Once
 }
 
 // NewClient creates client storage, generates keys, connects, and registers
@@ -224,6 +222,9 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 		return nil, err
 	}
 
+	//initilize the auth tracker
+	c.auth = auth.NewManager(c.switchboard, c.storage, c.network)
+
 	return c, nil
 }
 
@@ -256,6 +257,8 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 //		Responds to sent rekeys and executes them
 //   - KeyExchange Confirm (/keyExchange/confirm.go)
 //		Responds to confirmations of successful rekey operations
+//   - Auth Callback (/auth/callback.go)
+//      Handles both auth confirm and requests
 func (c *Client) StartNetworkFollower() error {
 	jww.INFO.Printf("StartNetworkFollower()")
 
@@ -264,6 +267,9 @@ func (c *Client) StartNetworkFollower() error {
 		return errors.WithMessage(err, "Failed to Start the Network Follower")
 	}
 
+	stopAuth := c.auth.StartProcessies()
+	c.runner.Add(stopAuth)
+
 	stopFollow, err := c.network.Follow()
 	if err != nil {
 		return errors.WithMessage(err, "Failed to start following "+
diff --git a/auth/callback.go b/auth/callback.go
index a8eed00f1c5b30b51634a6bfb826ca183606d368..6e90610ca75ebd361e456c407a773a99b2366d03 100644
--- a/auth/callback.go
+++ b/auth/callback.go
@@ -3,39 +3,30 @@ package auth
 import (
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
-	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/contact"
-	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/storage/auth"
 	"gitlab.com/elixxir/client/storage/e2e"
 	"gitlab.com/elixxir/crypto/cyclic"
 	cAuth "gitlab.com/elixxir/crypto/e2e/auth"
 	"gitlab.com/elixxir/primitives/format"
-	"gitlab.com/xx_network/primitives/id"
 	"strings"
 )
 
 type RequestCallback func(requestor contact.Contact, message string)
 type ConfirmCallback func(partner contact.Contact)
 
-func RegisterCallbacks(rcb RequestCallback, ccb ConfirmCallback,
-	sw interfaces.Switchboard, storage *storage.Session,
-	net interfaces.NetworkManager) stoppable.Stoppable {
-
-	rawMessages := make(chan message.Receive, 1000)
-	sw.RegisterChannel("Auth", &id.ID{}, message.Raw, rawMessages)
+func (m *Manager) StartProcessies() stoppable.Stoppable {
 
 	stop := stoppable.NewSingle("Auth")
-	authStore := storage.Auth()
-	grp := storage.E2e().GetGroup()
+	authStore := m.storage.Auth()
+	grp := m.storage.E2e().GetGroup()
 
 	go func() {
 		select {
 		case <-stop.Quit():
 			return
-		case msg := <-rawMessages:
+		case msg := <-m.rawMessages:
 			//lookup the message, check if it is an auth request
 			cmixMsg := format.Unmarshal(msg.Payload)
 			fp := cmixMsg.GetKeyFP()
@@ -50,26 +41,24 @@ func RegisterCallbacks(rcb RequestCallback, ccb ConfirmCallback,
 			}
 
 			//denote that the message is not garbled
-			storage.GetGarbledMessages().Remove(cmixMsg)
+			m.storage.GetGarbledMessages().Remove(cmixMsg)
 
 			switch fpType {
 			// if it is general, that means a new request has been received
 			case auth.General:
-				handleRequest(cmixMsg, myHistoricalPrivKey, grp, storage, rcb,
-					ccb, net)
+				m.handleRequest(cmixMsg, myHistoricalPrivKey, grp)
 			// if it is specific, that means the original request was sent
 			// by this users and a confirmation has been received
 			case auth.Specific:
-				handleConfirm(cmixMsg, sr, ccb, storage, grp, net)
+				m.handleConfirm(cmixMsg, sr, grp)
 			}
 		}
 	}()
 	return stop
 }
 
-func handleRequest(cmixMsg format.Message, myHistoricalPrivKey *cyclic.Int,
-	grp *cyclic.Group, storage *storage.Session, rcb RequestCallback,
-	ccb ConfirmCallback, net interfaces.NetworkManager) {
+func (m *Manager) handleRequest(cmixMsg format.Message,
+	myHistoricalPrivKey *cyclic.Int, grp *cyclic.Group) {
 	//decode the outer format
 	baseFmt, partnerPubKey, err := handleBaseFormat(cmixMsg, grp)
 	if err != nil {
@@ -116,14 +105,14 @@ func handleRequest(cmixMsg format.Message, myHistoricalPrivKey *cyclic.Int,
 	// if it does and the keys used are the same as we have, send a
 	// confirmation in case there are state issues.
 	// do not store
-	if _, err := storage.E2e().GetPartner(partnerID); err == nil {
+	if _, err := m.storage.E2e().GetPartner(partnerID); err == nil {
 		jww.WARN.Printf("Recieved Auth request for %s, "+
 			"channel already exists. Ignoring", partnerID)
 		//exit
 		return
 	} else {
 		//check if the relationship already exists,
-		rType, sr2, _, err := storage.Auth().GetRequest(partnerID)
+		rType, sr2, _, err := m.storage.Auth().GetRequest(partnerID)
 		if err != nil && !strings.Contains(err.Error(), auth.NoRequest) {
 			// if another error is recieved, print it and exist
 			jww.WARN.Printf("Recieved new Auth request for %s, "+
@@ -142,8 +131,8 @@ func handleRequest(cmixMsg format.Message, myHistoricalPrivKey *cyclic.Int,
 			// then exit, nothing else needed
 			case auth.Sent:
 				// do the confirmation
-				if err := doConfirm(sr2, grp, partnerPubKey, ecrFmt.GetOwnership(),
-					storage, ccb, net); err != nil {
+				if err := m.doConfirm(sr2, grp, partnerPubKey,
+					ecrFmt.GetOwnership()); err != nil {
 					jww.WARN.Printf("Confirmation failed: %s", err)
 				}
 				//exit
@@ -172,26 +161,29 @@ func handleRequest(cmixMsg format.Message, myHistoricalPrivKey *cyclic.Int,
 	// fixme: the client will never be notified of the channel creation if a
 	// crash occurs after the store but before the conclusion of the callback
 	//create the auth storage
-	if err = storage.Auth().AddReceived(c); err != nil {
+	if err = m.storage.Auth().AddReceived(c); err != nil {
 		jww.WARN.Printf("failed to store contact Auth "+
 			"Request: %s", err)
 		return
 	}
 
-	//call the callback
-
-	go rcb(c, msg)
+	//  fixme: if a crash occurs before or during the calls, the notification
+	//  will never be sent.
+	cbList := m.requestCallbacks.Get(c.ID)
+	for _, cb := range cbList {
+		rcb := cb.(RequestCallback)
+		go rcb(c, msg)
+	}
 	return
 }
 
-func handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
-	ccb ConfirmCallback, storage *storage.Session, grp *cyclic.Group,
-	net interfaces.NetworkManager) {
+func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
+	grp *cyclic.Group) {
 	// check if relationship already exists
-	if m, err := storage.E2e().GetPartner(sr.GetPartner()); m != nil || err == nil {
+	if mgr, err := m.storage.E2e().GetPartner(sr.GetPartner()); mgr != nil || err == nil {
 		jww.WARN.Printf("Cannot confirm auth for %s, channel already "+
 			"exists.", sr.GetPartner())
-		storage.Auth().Fail(sr.GetPartner())
+		m.storage.Auth().Fail(sr.GetPartner())
 		return
 	}
 
@@ -199,7 +191,7 @@ func handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
 	baseFmt, partnerPubKey, err := handleBaseFormat(cmixMsg, grp)
 	if err != nil {
 		jww.WARN.Printf("Failed to handle auth confirm: %s", err)
-		storage.Auth().Fail(sr.GetPartner())
+		m.storage.Auth().Fail(sr.GetPartner())
 		return
 	}
 
@@ -211,7 +203,7 @@ func handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
 	if !success {
 		jww.WARN.Printf("Recieved auth confirmation failed its mac " +
 			"check")
-		storage.Auth().Fail(sr.GetPartner())
+		m.storage.Auth().Fail(sr.GetPartner())
 		return
 	}
 
@@ -219,22 +211,20 @@ func handleConfirm(cmixMsg format.Message, sr *auth.SentRequest,
 	if err != nil {
 		jww.WARN.Printf("Failed to unmarshal auth confirmation's "+
 			"encrypted payload: %s", err)
-		storage.Auth().Fail(sr.GetPartner())
+		m.storage.Auth().Fail(sr.GetPartner())
 		return
 	}
 
 	// finalize the confirmation
-	if err := doConfirm(sr, grp, partnerPubKey, ecrFmt.GetOwnership(),
-		storage, ccb, net); err != nil {
+	if err := m.doConfirm(sr, grp, partnerPubKey, ecrFmt.GetOwnership()); err != nil {
 		jww.WARN.Printf("Confirmation failed: %s", err)
-		storage.Auth().Fail(sr.GetPartner())
+		m.storage.Auth().Fail(sr.GetPartner())
 		return
 	}
 }
 
-func doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
-	partnerPubKey *cyclic.Int, ownershipProof []byte, storage *storage.Session,
-	ccb ConfirmCallback, net interfaces.NetworkManager) error {
+func (m *Manager) doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
+	partnerPubKey *cyclic.Int, ownershipProof []byte) error {
 	// verify the message came from the intended recipient
 	if !cAuth.VerifyOwnershipProof(sr.GetMyPrivKey(),
 		sr.GetPartnerHistoricalPubKey(), grp, ownershipProof) {
@@ -245,7 +235,7 @@ func doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
 	// fixme: channel can get into a bricked state if the first save occurs and
 	// the second does not
 	p := e2e.GetDefaultSessionParams()
-	if err := storage.E2e().AddPartner(sr.GetPartner(),
+	if err := m.storage.E2e().AddPartner(sr.GetPartner(),
 		partnerPubKey, sr.GetMyPrivKey(), p, p); err != nil {
 		return errors.Errorf("Failed to create channel with partner (%s) "+
 			"after confirmation: %+v",
@@ -254,7 +244,7 @@ func doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
 
 	// delete the in progress negotiation
 	// this undoes the request lock
-	if err := storage.Auth().Delete(sr.GetPartner()); err != nil {
+	if err := m.storage.Auth().Delete(sr.GetPartner()); err != nil {
 		return errors.Errorf("UNRECOVERABLE! Failed to delete in "+
 			"progress negotiation with partner (%s) after confirmation: %+v",
 			sr.GetPartner(), err)
@@ -268,11 +258,15 @@ func doConfirm(sr *auth.SentRequest, grp *cyclic.Group,
 		Facts:          make([]contact.Fact, 0),
 	}
 
-	//  fixme: if a crash occurs before or during the call, the notification
+	//  fixme: if a crash occurs before or during the calls, the notification
 	//  will never be sent.
-	go ccb(c)
+	cbList := m.confirmCallbacks.Get(c.ID)
+	for _, cb := range cbList {
+		ccb := cb.(ConfirmCallback)
+		go ccb(c)
+	}
 
-	net.CheckGarbledMessages()
+	m.net.CheckGarbledMessages()
 
 	return nil
 }
diff --git a/auth/callbacks.go b/auth/callbacks.go
new file mode 100644
index 0000000000000000000000000000000000000000..ab6a2ead168f2ba363373371e6d9c43a61707cb0
--- /dev/null
+++ b/auth/callbacks.go
@@ -0,0 +1,70 @@
+package auth
+
+import (
+	"gitlab.com/xx_network/primitives/id"
+	"sync"
+)
+
+type callbackMap struct {
+	generalCallback  []interface{}
+	specificCallback map[id.ID]interface{}
+	overrideCallback []interface{}
+	mux              sync.RWMutex
+}
+
+func newCallbackMap() *callbackMap {
+	return &callbackMap{
+		generalCallback:  make([]interface{}, 0),
+		specificCallback: make(map[id.ID]interface{}),
+		overrideCallback: make([]interface{}, 0),
+	}
+}
+
+//adds a general callback. This will be preempted by any specific callback
+func (cm *callbackMap) AddGeneral(cb interface{}) {
+	cm.mux.Lock()
+	cm.generalCallback = append(cm.generalCallback, cb)
+	cm.mux.Unlock()
+}
+
+//adds an override callback. This will NOT be preempted by any callback
+func (cm *callbackMap) AddOverride(cb interface{}) {
+	cm.mux.Lock()
+	cm.overrideCallback = append(cm.overrideCallback, cb)
+	cm.mux.Unlock()
+}
+
+// adds a callback for a specific user ID. Only only callback can exist for a
+// user ID. False will be returned if a callback already exists and the new
+// one was not added
+func (cm *callbackMap) AddSpecific(id *id.ID, cb interface{}) bool {
+	cm.mux.Lock()
+	defer cm.mux.Unlock()
+	if _, ok := cm.specificCallback[*id]; ok {
+		return false
+	}
+	cm.specificCallback[*id] = cb
+	return true
+}
+
+// removes a callback for a specific user ID if it exists.
+func (cm *callbackMap) RemoveSpecific(id *id.ID) {
+	cm.mux.Lock()
+	defer cm.mux.Unlock()
+	delete(cm.specificCallback, *id)
+}
+
+//get all callback which fit with the passed id
+func (cm *callbackMap) Get(id *id.ID) []interface{} {
+	cm.mux.RLock()
+	defer cm.mux.RUnlock()
+	cbList := cm.overrideCallback
+
+	if specific, ok := cm.specificCallback[*id]; ok {
+		cbList = append(cbList, specific)
+	} else {
+		cbList = append(cbList, cm.generalCallback)
+	}
+
+	return cbList
+}
diff --git a/auth/manager.go b/auth/manager.go
new file mode 100644
index 0000000000000000000000000000000000000000..9577e99133bb0ff44d7dce2b2786795da120ba30
--- /dev/null
+++ b/auth/manager.go
@@ -0,0 +1,83 @@
+package auth
+
+import (
+	"gitlab.com/elixxir/client/interfaces"
+	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type Manager struct {
+	requestCallbacks *callbackMap
+	confirmCallbacks *callbackMap
+
+	rawMessages chan message.Receive
+
+	storage *storage.Session
+	net     interfaces.NetworkManager
+}
+
+func NewManager(sw interfaces.Switchboard, storage *storage.Session,
+	net interfaces.NetworkManager) *Manager {
+	m := &Manager{
+		requestCallbacks: newCallbackMap(),
+		confirmCallbacks: newCallbackMap(),
+		rawMessages:      make(chan message.Receive, 1000),
+		storage:          storage,
+		net:              net,
+	}
+
+	sw.RegisterChannel("Auth", &id.ID{}, message.Raw, m.rawMessages)
+
+	return m
+}
+
+// Adds a general callback to be used on auth requests. This will be preempted
+// by any specific callback
+func (m *Manager) AddGeneralRequestCallback(cb RequestCallback) {
+	m.requestCallbacks.AddGeneral(cb)
+}
+
+// Adds a general callback to be used on auth requests. This will not be
+// preempted by any specific callback. It is recommended that the specific
+// callbacks are used, this is primarily for debugging.
+func (m *Manager) AddOverrideRequestCallback(cb RequestCallback) {
+	m.requestCallbacks.AddOverride(cb)
+}
+
+// Adds a specific callback to be used on auth requests. This will preempt a
+// general callback, meaning the request will be heard on this callback and not
+// the general. Request will still be heard on override callbacks.
+func (m *Manager) AddSpecificRequestCallback(id *id.ID, cb RequestCallback) {
+	m.requestCallbacks.AddSpecific(id, cb)
+}
+
+// Removes a specific callback to be used on auth requests.
+func (m *Manager) RemoveSpecificRequestCallback(id *id.ID) {
+	m.requestCallbacks.RemoveSpecific(id)
+}
+
+// Adds a general callback to be used on auth confirms. This will be preempted
+// by any specific callback
+func (m *Manager) AddGeneralConfirmCallback(cb ConfirmCallback) {
+	m.confirmCallbacks.AddGeneral(cb)
+}
+
+// Adds a general callback to be used on auth confirms. This will not be
+// preempted by any specific callback. It is recommended that the specific
+// callbacks are used, this is primarily for debugging.
+func (m *Manager) AddOverrideConfirmCallback(cb ConfirmCallback) {
+	m.confirmCallbacks.AddOverride(cb)
+}
+
+// Adds a specific callback to be used on auth confirms. This will preempt a
+// general callback, meaning the request will be heard on this callback and not
+// the general. Request will still be heard on override callbacks.
+func (m *Manager) AddSpecificConfirmCallback(id *id.ID, cb ConfirmCallback) {
+	m.confirmCallbacks.AddSpecific(id, cb)
+}
+
+// Removes a specific callback to be used on auth confirm.
+func (m *Manager) RemoveSpecificConfirmCallback(id *id.ID) {
+	m.confirmCallbacks.RemoveSpecific(id)
+}
diff --git a/interfaces/auth.go b/interfaces/auth.go
new file mode 100644
index 0000000000000000000000000000000000000000..836ba0cf95d56d58151b5d99c6dd72cc4a12538f
--- /dev/null
+++ b/interfaces/auth.go
@@ -0,0 +1,35 @@
+package interfaces
+
+import (
+	"gitlab.com/elixxir/client/auth"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+type Auth interface {
+	// Adds a general callback to be used on auth requests. This will be preempted
+	// by any specific callback
+	AddGeneralRequestCallback(cb auth.RequestCallback)
+	// Adds a general callback to be used on auth requests. This will not be
+	// preempted by any specific callback. It is recommended that the specific
+	// callbacks are used, this is primarily for debugging.
+	AddOverrideRequestCallback(cb auth.RequestCallback)
+	// Adds a specific callback to be used on auth requests. This will preempt a
+	// general callback, meaning the request will be heard on this callback and not
+	// the general. Request will still be heard on override callbacks.
+	AddSpecificRequestCallback(id *id.ID, cb auth.RequestCallback)
+	// Removes a specific callback to be used on auth requests.
+	RemoveSpecificRequestCallback(id *id.ID)
+	// Adds a general callback to be used on auth confirms. This will be preempted
+	// by any specific callback
+	AddGeneralConfirmCallback(cb auth.ConfirmCallback)
+	// Adds a general callback to be used on auth confirms. This will not be
+	// preempted by any specific callback. It is recommended that the specific
+	// callbacks are used, this is primarily for debugging.
+	AddOverrideConfirmCallback(cb auth.ConfirmCallback)
+	// Adds a specific callback to be used on auth confirms. This will preempt a
+	// general callback, meaning the request will be heard on this callback and not
+	// the general. Request will still be heard on override callbacks.
+	AddSpecificConfirmCallback(id *id.ID, cb auth.ConfirmCallback)
+	// Removes a specific callback to be used on auth confirm.
+	RemoveSpecificConfirmCallback(id *id.ID)
+}