Docs Menu
Docs Home
/ /
Atlas Device SDKs
/

Link User Identities

Atlas Device SDK provides many authentication providers to log users into your app. Each provider has its own credentials that create a unique user identity. The SDK lets you merge multiple identities into a single user account.

User identities must be linked prior to logging a user in. Once the user is logged in, you cannot link the credential used to login to the user account. Also, you cannot link multiple email/password identities together.

Consider an application that offers anonymous login, which allows users to explore the app without registering. If a user wants to continue using the application, they can create a permanent account with an authentication provider intended to persist user data over a longer period, such as email/password authentication. The SDK creates a new identity belonging to a new User object. The app can then link the new identity with the current user.

Note

Depending on how you have configured email/password authentication, there may be additional steps (confirming the email address, for example) before the new account is created and can be linked.

You can link identities using the LinkCredentialsAsync(). This links the identity belonging to the credentials to the logged-in User object.

// 1) A user logs on anonymously:
var anonUser = await app.LogInAsync(Credentials.Anonymous());
// 2) They create some data, and then decide they want to save
// it, which requires creating an Email/Password account.
// 3) We prompt the user to log in, and then use that info to
// register the new EmailPassword user, and then generate an
// EmailPassword credential to link the existing anonymous
// account:
var email = "caleb@mongodb.com";
var password = "MySekritPwd";
await app.EmailPasswordAuth.RegisterUserAsync(
email, password);
var officialUser = await anonUser.LinkCredentialsAsync(
Credentials.EmailPassword(email, password));

In the example above, we must first register the new email/password user before linking. If you are using any of the other Auth Providers, this step is unnecessary. The following example uses Google authentication instead of EmailPassword.

You can link identities by passing the Credentials that you want to link to User.linkCredentials().

final linkedCredentialUser =
await user.linkCredentials(additionalCredentials);

In the example below, we register an anonymous user, then later register an email/password user and link the credentials.

You can link identities using linkCredentials(). This links the identity that belongs to the credential to a logged-in User object.

You link identities using linkCredentials. This links the identity belonging to the credential to the logged-in User.

You can link identities using -linkUserWithCredentials:completion:. This links the identity that belongs to the credential to a logged-in User object.

You can link identities using linkUser(credentials:). This links the identity that belongs to the credential to a logged-in User object.

let app = App(id: YOUR_APP_SERVICES_APP_ID)
func logInAnonymously() {
app.login(credentials: Credentials.anonymous) { (result) in
switch result {
case .failure(let error):
print("Failed to log in: \(error.localizedDescription)")
case .success(let user):
// User uses app, then later registers an account
registerNewAccount(anonymousUser: user)
}
}
}
func registerNewAccount(anonymousUser: User) {
let email = "swift-link@example.com"
let password = "ganondorf"
app.emailPasswordAuth.registerUser(email: email, password: password) { (error) in
guard error == nil else {
print("Failed to register new account: \(error!.localizedDescription)")
return
}
// Successfully created account, now link it
// with the existing anon user
link(user: anonymousUser, with: Credentials.emailPassword(email: email, password: password))
}
}
func link(user: User, with credentials: Credentials) {
user.linkUser(credentials: credentials) { (result) in
switch result {
case .failure(let error):
print("Failed to link user: \(error.localizedDescription)")
case .success(let user):
print("Successfully linked user: \(user)")
}
}
}
logInAnonymously()

The SDK also provides an async/await version of User.linkUser.

You can link identities using linkCredentials(). This links the identity that belongs to the credential to a logged-in User object.

var anonUser = await app.LogInAsync(Credentials.Anonymous());
var officialUser = await anonUser.LinkCredentialsAsync(
Credentials.Google("<google-token>", GoogleCredentialType.AuthCode));
// on app start without registration
final anonymousUser = await app.logIn(Credentials.anonymous());
// ... user interacts with app
//... user decides to sign up for app with email/password auth
final authProvider = EmailPasswordAuthProvider(app);
await authProvider.registerUser(USERNAME, PASSWORD);
// link email/password credentials to anonymous user's credentials
final linkedCredentialUser = await anonymousUser
.linkCredentials(Credentials.emailPassword(USERNAME, PASSWORD));
// The user has previously created an email/password account
user.linkCredentialsAsync(
Credentials.emailPassword(email, password), result -> {
if (result.isSuccess()) {
Log.v("EXAMPLE", "Successfully linked existing user " +
"identity with email/password user: " + result.get());
} else {
Log.e("EXAMPLE", "Failed to link user identities with: " +
result.getError());
}
});
async function linkAccounts(user, email, password) {
const emailPasswordUserCredentials = Realm.Credentials.emailPassword(
email,
password
);
const linkedAccount = await user.linkCredentials(
emailPasswordUserCredentials
);
return linkedAccount;
}
val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val user = app.login(Credentials.anonymous()) // logs in with an anonymous user
// registers an email/password user
app.emailPasswordAuth.registerUser(email, password)
// links anonymous user with email/password credentials
user.linkCredentials(Credentials.emailPassword(email, password))
}
// The user has previously created an email/password account
user.linkCredentialsAsync(
Credentials.emailPassword(
email,
password
)
) { result ->
if (result.isSuccess) {
Log.v(
"EXAMPLE",
"Successfully linked existing user identity " +
"with email/password user: ${result.get()}"
)
} else {
Log.e(
"EXAMPLE",
"Failed to link user identities with: ${result.error}"
)
}
}
@interface LinkIdentitiesExample : NSObject
@end
@implementation LinkIdentitiesExample {
RLMApp *app;
RLMUser *anonymousUser;
}
// Entry-point for example.
- (void)runExample {
app = [RLMApp appWithId:YOUR_APP_ID];
[self logInAnonymously];
}
- (void)logInAnonymously {
[app loginWithCredential:[RLMCredentials anonymousCredentials] completion:^(RLMUser *user, NSError *error) {
if (error != nil) {
NSLog(@"Failed to log in: %@", [error localizedDescription]);
return;
}
// User uses app, then later registers an account
[self registerNewAccountAsAnonymousUser: user];
}];
}
- (void)registerNewAccountAsAnonymousUser:(RLMUser *)user {
NSString *email = @"link2@example.com";
NSString *password = @"ganondorf";
[[app emailPasswordAuth] registerUserWithEmail:email password:password completion:^(NSError *error) {
if (error != nil) {
NSLog(@"Failed to register new account: %@", [error localizedDescription]);
return;
}
// Successfully created account, now link it
// with the existing anon user
[self linkUser:self->anonymousUser withCredentials:[RLMCredentials credentialsWithEmail:email password:password]];
}];
}
- (void)linkUser:(RLMUser *)user withCredentials:(RLMCredentials *)credentials {
[[app currentUser] linkUserWithCredentials:credentials completion:^(RLMUser *user, NSError *error) {
if (error != nil) {
NSLog(@"Failed to link user: %@", [error localizedDescription]);
return;
}
NSLog(@"Successfully linked user: %@", user);
}];
}
@end
let app = App(id: YOUR_APP_SERVICES_APP_ID)
func logInAnonymously() async throws -> User {
let anonymousUser = try await app.login(credentials: Credentials.anonymous)
// User uses app, then later registers an account
let newAccountLinkedUser = try await registerNewAccount(anonymousUser: anonymousUser)
return newAccountLinkedUser
}
func registerNewAccount(anonymousUser: User) async throws -> User {
let email = "swift-async-link@example.com"
let password = "ganondorf"
try await app.emailPasswordAuth.registerUser(email: email, password: password)
// Successfully created account, now link it
// with the existing anon user
let linkedUser = try await link(user: anonymousUser, with: Credentials.emailPassword(email: email, password: password))
return linkedUser
}
func link(user: User, with credentials: Credentials) async throws -> User {
try await user.linkUser(credentials: credentials)
}
do {
let linkedUser = try await logInAnonymously()
print("Successfully linked user async: \(linkedUser)")
} catch {
print("Failed to link user: \(error.localizedDescription)")
}
async function linkAccounts(
user: Realm.User,
email: string,
password: string
) {
const emailPasswordUserCredentials = Realm.Credentials.emailPassword(
email,
password
);
const linkedAccount = await user.linkCredentials(
emailPasswordUserCredentials
);
return linkedAccount;
}

Back

Multi-User Applications

Next

Create & Manage User API Keys