diff --git a/auth/callback.go b/auth/callback.go
index 70b9c2843406205198cdb439666741b193c52518..6da4fd2fbd3ad612a7942cb2f7aac11337d6ee74 100644
--- a/auth/callback.go
+++ b/auth/callback.go
@@ -348,7 +348,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message,
 	var rndNum id.Round
 	if autoConfirm || resetSession {
 		// Call ConfirmRequestAuth to send confirmation
-		rndNum, err = m.ConfirmRequestAuth(c)
+		rndNum, err = m.confirmRequestAuth(c, true)
 		if err != nil {
 			jww.ERROR.Printf("Could not ConfirmRequestAuth: %+v",
 				err)
diff --git a/auth/confirm.go b/auth/confirm.go
index 28a5292aec2ad83f888c35e1f19feb32a55acea7..40ddc527dc1f43da6b5f5071d0670d1702369d16 100644
--- a/auth/confirm.go
+++ b/auth/confirm.go
@@ -32,6 +32,11 @@ func (m *Manager) ConfirmRequestAuth(partner contact.Contact) (id.Round, error)
 		return 0, errors.New("Cannot confirm authenticated message " +
 			"when the network is not healthy")
 	}
+	return m.confirmRequestAuth(partner, false)
+}
+
+func (m *Manager) confirmRequestAuth(partner contact.Contact, critical bool) (id.Round,
+	error) {
 
 	// Cannot confirm already established channels
 	if _, err := m.storage.E2e().GetPartner(partner.ID); err == nil {
@@ -156,15 +161,28 @@ func (m *Manager) ConfirmRequestAuth(partner contact.Contact) (id.Round, error)
 	param.IdentityPreimage = preimg
 	param.DebugTag = "auth.Confirm"
 	/*send message*/
+	if critical {
+		m.storage.GetCriticalRawMessages().AddProcessing(cmixMsg,
+			partner.ID)
+	}
 	round, _, err := m.net.SendCMIX(cmixMsg, partner.ID, param)
 	if err != nil {
 		// if the send fails just set it to failed, it will but automatically
 		// retried
 		jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+
 			"to transmit: %+v", partner.ID, cmixMsg.Digest(), err)
+		if critical {
+			m.storage.GetCriticalRawMessages().Failed(cmixMsg,
+				partner.ID)
+		}
 		return 0, errors.WithMessage(err, "Auth Confirm Failed to transmit")
 	}
 
+	if critical {
+		m.storage.GetCriticalRawMessages().Succeeded(cmixMsg,
+			partner.ID)
+	}
+
 	em := fmt.Sprintf("Confirm Request with %s (msgDigest: %s) sent on round %d",
 		partner.ID, cmixMsg.Digest(), round)
 	jww.INFO.Print(em)
diff --git a/auth/request.go b/auth/request.go
index cd32a5116b2f62d4da3cb90e5cfc3c8da94aba50..8f39fc9db835f30e41e51e6a6fe5db377aef666f 100644
--- a/auth/request.go
+++ b/auth/request.go
@@ -88,10 +88,12 @@ func requestAuth(partner, me contact.Contact, rng io.Reader, reset bool,
 	} else if err == nil {
 		switch rqType {
 		case auth.Receive:
-			// TODO: We've already received a request, so send a
-			//       confirmation instead?
-			return 0, errors.Errorf("Cannot send a request after " +
-				"receiving a request")
+			if reset {
+				storage.Auth().DeleteRequest(partner.ID)
+			} else {
+				return 0, errors.Errorf("Cannot send a " +
+					"request after receiving a request")
+			}
 		case auth.Sent:
 			resend = true
 		default:
diff --git a/backup/backup.go b/backup/backup.go
index 71ea5a210b8915be03f1f78458384caa2b4d8ac6..5280b8dc9257a86543c97b02244066b795f1b069 100644
--- a/backup/backup.go
+++ b/backup/backup.go
@@ -24,6 +24,7 @@ import (
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/crypto/backup"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/xx_network/primitives/id"
 )
 
 // Error messages.
@@ -149,7 +150,7 @@ func resumeBackup(updateBackupCb UpdateBackupFn, c *api.Client,
 	// Setting backup trigger in client
 	b.backupContainer.SetBackup(b.TriggerBackup)
 
-	jww.INFO.Print("Resumed backup with password loaded from storage.")
+	jww.INFO.Print("resumed backup with password loaded from storage.")
 
 	return b, nil
 }
@@ -302,9 +303,33 @@ func (b *Backup) assembleBackup() backup.Backup {
 
 	// Get contacts
 	bu.Contacts.Identities = b.store.E2e().GetPartners()
+	// Get pending auth requests
+	// NOTE: Received requests don't matter here, as those are either
+	// not yet noticed by user OR explicitly rejected.
+	bu.Contacts.Identities = append(bu.Contacts.Identities,
+		b.store.Auth().GetAllSentIDs()...)
+	jww.INFO.Printf("backup saw %d contacts", len(bu.Contacts.Identities))
+	jww.DEBUG.Printf("contacts in backup list: %+v", bu.Contacts.Identities)
+	//deduplicate list
+	bu.Contacts.Identities = deduplicate(bu.Contacts.Identities)
+
+	jww.INFO.Printf("backup saved %d contacts after deduplication",
+		len(bu.Contacts.Identities))
 
 	// Add the memoized JSON params
 	bu.JSONParams = b.jsonParams
 
 	return bu
 }
+
+func deduplicate(list []*id.ID) []*id.ID {
+	entryMap := make(map[id.ID]bool)
+	newList := make([]*id.ID, 0)
+	for i, _ := range list {
+		if _, value := entryMap[*list[i]]; !value {
+			entryMap[*list[i]] = true
+			newList = append(newList, list[i])
+		}
+	}
+	return newList
+}
diff --git a/bindings/restoreContacts.go b/bindings/restoreContacts.go
index b970c77a2ed8cbf5664f76a6754904edb9b8d0f0..aeead16fd7a7c94e4e4148d1291f1b6404f0a690 100644
--- a/bindings/restoreContacts.go
+++ b/bindings/restoreContacts.go
@@ -8,7 +8,9 @@
 package bindings
 
 import (
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/xxmutils"
+	"gitlab.com/elixxir/crypto/contact"
 	"gitlab.com/xx_network/primitives/id"
 )
 
@@ -74,11 +76,30 @@ func (r *RestoreContactsReport) GetRestoreContactsError() string {
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func RestoreContactsFromBackup(backupPartnerIDs []byte, client *Client,
-	udManager *UserDiscovery,
+	udManager *UserDiscovery, lookupCB LookupCallback,
 	updatesCb RestoreContactsUpdater) *RestoreContactsReport {
 
+	extLookupCB := func(c contact.Contact, myErr error) {
+		jww.INFO.Printf("extLookupCB triggered: %v, %v", c, myErr)
+		bindingsContact := &Contact{c: &c}
+		errStr := ""
+		if myErr != nil {
+			jww.WARN.Printf("restore err on lookup: %+v",
+				myErr)
+			errStr = myErr.Error()
+		}
+		if lookupCB != nil {
+			jww.INFO.Printf("Calling lookupCB(%+v, %+v)",
+				bindingsContact, errStr)
+			lookupCB.Callback(bindingsContact, errStr)
+		} else {
+			jww.WARN.Printf("nil external lookup callback")
+		}
+	}
+
 	restored, failed, errs, err := xxmutils.RestoreContactsFromBackup(
-		backupPartnerIDs, &client.api, udManager.ud, updatesCb)
+		backupPartnerIDs, &client.api, udManager.ud, extLookupCB,
+		updatesCb)
 
 	return &RestoreContactsReport{
 		restored: restored,
diff --git a/cmd/ud.go b/cmd/ud.go
index dc940811b9ff1888ae4b221b8fa8ad5accb66e7a..a8f6205a4fe173d62af1d9ef10c1b85574ad63e9 100644
--- a/cmd/ud.go
+++ b/cmd/ud.go
@@ -169,7 +169,7 @@ var udCmd = &cobra.Command{
 				jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err)
 			}
 			restored, _, _, err := xxmutils.RestoreContactsFromBackup(
-				idListFile, client, userDiscoveryMgr, nil)
+				idListFile, client, userDiscoveryMgr, nil, nil)
 			if err != nil {
 				jww.FATAL.Panicf("%+v", err)
 			}
diff --git a/storage/auth/store.go b/storage/auth/store.go
index f0a48c6d7dd1c80b19d6c11aac046bb4da9a209d..2d81f960cf767702f21b5401e26e780c0ff74603 100644
--- a/storage/auth/store.go
+++ b/storage/auth/store.go
@@ -9,6 +9,8 @@ package auth
 
 import (
 	"encoding/json"
+	"sync"
+
 	"github.com/cloudflare/circl/dh/sidh"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
@@ -20,7 +22,6 @@ import (
 	"gitlab.com/elixxir/primitives/format"
 	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/netTime"
-	"sync"
 )
 
 const NoRequest = "Request Not Found"
@@ -291,6 +292,20 @@ func (s *Store) GetAllReceived() []contact.Contact {
 	return cList
 }
 
+// GetAllReceived returns all pending received contact requests from storage.
+func (s *Store) GetAllSentIDs() []*id.ID {
+	s.mux.RLock()
+	defer s.mux.RUnlock()
+	cList := make([]*id.ID, 0, len(s.requests))
+	for key := range s.requests {
+		r := s.requests[key]
+		if r.rt == Sent {
+			cList = append(cList, r.sent.partner)
+		}
+	}
+	return cList
+}
+
 // GetFingerprint can return either a private key or a sentRequest if the
 // fingerprint is found. If it returns a sentRequest, then it takes the lock to
 // ensure there is only one operator at a time. The user of the API must release
diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go
index b64947418cb401ea797c99cc8c5935a60335bfb9..5074508c6d70f21057a0dffe3300035f66162b26 100644
--- a/xxmutils/restoreContacts.go
+++ b/xxmutils/restoreContacts.go
@@ -24,9 +24,12 @@ import (
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/client/ud"
 	"gitlab.com/elixxir/crypto/contact"
+	"gitlab.com/elixxir/primitives/fact"
 	"gitlab.com/xx_network/primitives/id"
 )
 
+type LookupCallback func(c contact.Contact, myErr error)
+
 // RestoreContactsFromBackup takes as input the jason output of the
 // `NewClientFromBackup` function, unmarshals it into IDs, looks up
 // each ID in user discovery, and initiates a session reset request.
@@ -36,7 +39,7 @@ import (
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
-	udManager *ud.Manager,
+	udManager *ud.Manager, lookupCB LookupCallback,
 	updatesCb interfaces.RestoreContactsUpdater) ([]*id.ID, []*id.ID,
 	[]error, error) {
 
@@ -66,6 +69,9 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 	}
 	lookupIDs, resetContacts, restored := checkRestoreState(idList, store)
 
+	jww.INFO.Printf("restoring %d backup partner IDs", len(lookupIDs))
+	jww.DEBUG.Printf("backup partner IDs to restore: %+v", lookupIDs)
+
 	// State variables, how many we have looked up successfully
 	// and how many we have already reset.
 	totalCnt := len(idList)
@@ -92,7 +98,8 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 	rsWg := &sync.WaitGroup{}
 	rsWg.Add(numRoutines)
 	for i := 0; i < numRoutines; i++ {
-		go LookupContacts(lookupCh, foundCh, failCh, udManager, lcWg)
+		go LookupContacts(lookupCh, foundCh, failCh, udManager, lookupCB,
+			lcWg)
 		go ResetSessions(resetContactCh, restoredCh, failCh, *client,
 			rsWg)
 	}
@@ -172,13 +179,13 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client,
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
 func LookupContacts(in chan *id.ID, out chan *contact.Contact,
-	failCh chan failure, udManager *ud.Manager,
+	failCh chan failure, udManager *ud.Manager, extLookupCB LookupCallback,
 	wg *sync.WaitGroup) {
 	defer wg.Done()
 	// Start looking up contacts with user discovery and feed this
 	// contacts channel.
 	for lookupID := range in {
-		c, err := LookupContact(lookupID, udManager)
+		c, err := LookupContact(lookupID, udManager, extLookupCB)
 		if err == nil {
 			out <- c
 			continue
@@ -220,8 +227,8 @@ func ResetSessions(in, out chan *contact.Contact, failCh chan failure,
 // xxDK users should not use this function. This function is used by
 // the mobile phone apps and are not intended to be part of the xxDK. It
 // should be treated as internal functions specific to the phone apps.
-func LookupContact(userID *id.ID, udManager *ud.Manager) (
-	*contact.Contact, error) {
+func LookupContact(userID *id.ID, udManager *ud.Manager,
+	extLookupCB LookupCallback) (*contact.Contact, error) {
 	// This is a little wonky, but wait until we get called then
 	// set the result to the contact objects details if there is
 	// no error
@@ -229,11 +236,23 @@ func LookupContact(userID *id.ID, udManager *ud.Manager) (
 	var result *contact.Contact
 	var err error
 	lookupCB := func(c contact.Contact, myErr error) {
-		defer waiter.Unlock()
-		if myErr != nil {
+		if myErr == nil {
+			newOwnership := make([]byte, len(c.OwnershipProof))
+			copy(newOwnership, c.OwnershipProof)
+			newFacts, _, _ := fact.UnstringifyFactList(
+				c.Facts.Stringify())
+			result = &contact.Contact{
+				ID:             c.ID.DeepCopy(),
+				DhPubKey:       c.DhPubKey.DeepCopy(),
+				OwnershipProof: newOwnership,
+				Facts:          newFacts,
+			}
+		} else {
 			err = myErr
+			result = nil
 		}
-		result = &c
+		waiter.Unlock()
+		extLookupCB(c, myErr)
 	}
 	// Take lock once to make sure I will wait
 	waiter.Lock()