Docs Menu
Docs Home
/ /
Atlas Device SDKs
/ /

Create and Authenticate Users - Kotlin SDK

On this page

  • App Services Users
  • Prerequisites
  • Register and Create a New User Account
  • Log In a User
  • Anonymous
  • Email/Password
  • Custom JWT
  • API Key
  • Custom Function
  • Google
  • Facebook
  • Apple
  • Retrieve Current User
  • Log In Offline
  • Manage User Tokens
  • Get a User Access Token
  • Configure Refresh Token Expiration
  • Log a User Out
  • Observe Authentication Changes

To access Atlas App Services, you must first authenticate a user with an App Services authentication provider. This page describes how to authenticate App Services App users with the Realm Kotlin SDK. Refer to Authenticate & Manage Users in the App Services documentation for more information.

Important

Google and Apple Account Deletion Requirements

Google and Apple require that applications listed through their respective App Stores must give any user who creates an account the option to delete the account. Whether you use an authentication method where you must manually register a user, such as email/password authentication, or one that that automatically creates a user, such as Sign-In with Apple, you must implement user account deletion.

Atlas App Services provides the following built-in authentication providers to log users in and out of a client app:

  • Anonymous users

  • Email/password combinations

  • API keys

  • OAuth 2.0 through Facebook, Google, and Apple ID

  • Custom JWT

  • Custom Function

Upon successful log in, App Services begins a user session for the user. App Services manages sessions with access tokens and refresh tokens, and the Kotlin SDK supplies the logic to manage tokens and provide them with requests. For more information on managing user sessions and tokens, refer to User Sessions in the App Services documentation.

Once you have a logged-in user, you can:

You can also log multiple users in to an app simultaneously on a single device. Refer to Manage Multi-User Applications - Kotlin SDK for more information.

To authenticate users through Atlas App Services, you must have an App Services App with one or more authentication providers enabled.

To set up an App Services App with authentication providers, complete the following:

  1. Connect your App to Atlas App Services

  2. Enable and Configure Authentication Providers in the App Services documentation

Tip

You can enable multiple authentication providers. If a user authenticates using more than one method, you can link the user identities for each method to a single user account.

Atlas App Services registers a user differently depending on the authentication provider:

  • If you are using email/password authentication, users must first register and confirm their email and password before they can authenticate.

  • If you are using Google, Facebook, Apple, or Custom JWT, registration is handled by these third-party services.

  • If you are using anonymous authentication, you don't need to register. Anonymous users do not require registration.

The first time the user successfully authenticates to your App, Atlas App Services automatically creates a User object, which contains a unique identifier and provider-specific user metadata. To learn more about the user object that App Services provides the Kotlin SDK, refer to Read User Metadata in the App Services documentation.

To authenticate and log users in to your App, first instantiate a Credentials object containing the credentials associated with the authentication provider, and then pass it to app.login(). Each authentication provider corresponds to a static helper method used to instantiate Credentials objects for that authentication provider.

// Instantiate your App Services App
val app = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
// Log in the user with the credentials associated
// with the authentication provider
// If successful, returns an authenticated `User` object
val user = app.login(credentials)
// ... work with the user ...
}

If successful, app.login() returns a User object. In the event of a failure, app.login() throws an exception of type AppException.

Tip

You can get the authentication provider type used to log in a user through the user.provider property. If the user is currently logged out, the most recent provider used to log in the user is returned.

Anonymous authentication enables users to log in to your application with short-term accounts that store no persistent personal information. You might use this to allow users to try your app before they sign up for an account or while developing and testing your app. Anonymous users do not require registration. Refer to Anonymous Authentication in the App Services documentation for more information.

To log in with anonymous authentication, create an anonymous credential by calling Credentials.anonymous(), and then pass the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val anonymousCredentials = Credentials.anonymous()
val user = app.login(anonymousCredentials)
}

By default, the Kotlin SDK reuses the same anonymous user if that user has not logged out. If you want to create more than one anonymous user, set reuseExisting = false when logging in with additional anonymous credentials:

// Logs in with an anonymous user
val anonUser = app.login(Credentials.anonymous())
// Logs in with a new, different anonymous user
val otherAnonUser =
app.login(Credentials.anonymous(reuseExisting = false))

The email/password authentication provider enables users to log in to your application with an email username and a password. Refer to Email/Password Authentication in the App Services documentation for more information.

Important

Email/Password Users Require Registration

Email/password authentication requires that you register and then confirm the user-provided email and password before the user can authenticate to an App Services App. Learn how to register email/password users.

To log in with email/password authentication, create an email/password credential by calling Credentials.emailPassword() with the user's registered email and password, and then pass the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val emailPasswordCredentials = Credentials.emailPassword(email, password)
val user = app.login(emailPasswordCredentials)
}

The Custom JWT authentication provider enables users to log in to your application with a custom JSON Web Token (JWT). Registration for JWT authentication is handled by the JWT provider. Refer to Custom JWT Authentication in the App Services documentation for more information.

To log in with JWT authentication, create a JWT credential by calling Credentials.jwt() with the user's JWT, and then pass the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
// Registration is handled by the JWT provider
val jwtCredentials = Credentials.jwt(jwtToken)
val user = app.login(jwtCredentials)
}

The API Key authentication provider enables authenticated non-anonymous users to log in to your application with an API key. Refer to API Key Authentication in the App Services documentation for more information.

To log in with API key authentication, create an API Key credential by calling Credentials.apiKey() with the user's API key, and then passing the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val user = app.login(Credentials.apiKey(key))
}

User API keys are generated automatically and managed by the Kotlin SDK. Learn how to Manage User API Keys - Kotlin SDK.

The Custom Function authentication provider enables users to log in to your application using custom authentication logic handled by an Atlas Function. Refer to Custom Function Authentication in the App Services documentation for more information.

To log in with Custom Function authentication, pass your custom arguments as a payload to Credentials.customFunction(), and then pass the generated credential to app.login():

// Create custom arguments for your Atlas Function
val customCredentials = Credentials.customFunction(
payload = mapOf("username" to "bob")
)
val user = app.login(customCredentials)

Learn how to Call an Atlas Function - Kotlin SDK.

New in version 1.9.0.

You can serialize data for a Custom Function credential using an EJSON encoder. For more information, including examples, refer to EJSON Encoding for Atlas.

The Google authentication provider allows you to authenticate users through their existing Google account using an OAuth 2.0 token. Refer to Google Authentication in the App Services documentation for more information.

Before you can authenticate users with Google, you must set up your application for Google User authentication:

  1. In the Google Cloud Platform console, create an OAuth 2.0 client ID of type "Web application".

  2. Configure your backend App to use that client ID and the associated client secret.

  3. Enable OpenID Connect on the backend.

Use Google's official Sign-In for Android to authenticate Google users in your Android application. The following code implements this flow, starting with a method call to loginWithGoogle():

fun loginWithGoogle() {
val gso = GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("YOUR WEB APPLICATION CLIENT ID FOR GOOGLE AUTH")
.build()
val googleSignInClient = GoogleSignIn.getClient(activity, gso)
val signInIntent: Intent = googleSignInClient.signInIntent
val resultLauncher: ActivityResultLauncher<Intent> =
// Note: this activity MUST inherit from ComponentActivity or AppCompatActivity to use this API
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result ->
val task: Task<GoogleSignInAccount> =
GoogleSignIn.getSignedInAccountFromIntent(result.data)
handleSignInResult(task)
}
resultLauncher.launch(signInIntent)
}
fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
if (completedTask.isSuccessful) {
val account: GoogleSignInAccount? = completedTask.getResult(ApiException::class.java)
val token: String = account?.idToken!!
val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val user = app.login(Credentials.google(token, GoogleAuthType.ID_TOKEN))
}
} else {
Log.e("AUTH", "Google Auth failed: ${completedTask.exception}")
}
} catch (e: ApiException) {
Log.e("AUTH", "Failed to authenticate using Google OAuth: " + e.message);
}
}

Tip

To learn more about Google Sign-In for Android, check out the official Google Sign-In for Android Integration Guide.

Kotlin Multiplatform (KMP) supports many environments, but this example shows sign-in on the Android platform. For information about signing into a Google account on Apple platforms, refer to the Swift SDK Example.

The Facebook authentication provider allows you to authenticate users through a Facebook app using their existing Facebook account. Refer to Facebook Authentication in the App Services documentation for more information.

Before you can authenticate users with Facebook, you must set up the authentication flow for your application by following the official Facebook Login for Android Quickstart.

In the login completion handler, get the logged in user's access token from the Facebook LoginResult. Use the access token to create a Facebook credential by calling Credentials.facebook() with the user's access token, and then pass the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
FacebookSdk.setApplicationId(YOUR_FACEBOOK_SDK_APP_ID)
FacebookSdk.sdkInitialize(activity)
val callbackManager = CallbackManager.Factory.create()
LoginManager.getInstance().registerCallback(
callbackManager,
object : FacebookCallback<LoginResult> {
override fun onSuccess(loginResult: LoginResult) {
// Signed in successfully, forward credentials to MongoDB Realm.
val accessToken = loginResult.accessToken
runBlocking {
val user = app.login(Credentials.facebook(accessToken.token))
}
}
override fun onCancel() {
Log.v("AUTH", "Cancelled Facebook login")
}
override fun onError(exception: FacebookException) {
Log.e("AUTH", "Failed to authenticate with Facebook: ${exception.message}")
}
})

Important

Do Not Store Facebook Profile Picture URLs

Facebook profile picture URLs include the user's access token to grant permission to the image. To ensure security, do not store a URL that includes a user's access token. Instead, access the URL directly from the user's metadata fields when you need to fetch the image.

Kotlin Multiplatform (KMP) supports many environments, but this example shows sign-in on the Android platform. For information about signing into a Facebook account on Apple platforms, refer to the Swift SDK Example.

The Sign-in with Apple authentication provider enables users to log in to your application with a custom token provided by Apple. Refer to Apple ID Authentication in the App Services documentation for more information.

To log in with Apple authentication, create an Apple credential by calling Credentials.apple() with the user's token, and then pass the generated credential to app.login():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
// Registration is handled by Apple
val appleCredentials = Credentials.apple(idToken)
val user = app.login(appleCredentials)
}

Kotlin Multiplatform (KMP) supports many environments, but this example shows sign-in on the Android platform. For information about signing in with Apple on Apple platforms, see the Swift SDK Example.

You can retrieve the currently logged-in user with the App.currentUser property:

val user = app.currentUser

If you have multiple users logged in to your app, this returns the last valid user that logged in or returns null if there are no logged-in users. Refer to Manage Multi-User Applications - Kotlin SDK for more information.

Note that the currentUser object is persisted in local storage, so even if the app shuts down after the initial authentication, you do not need to call logIn again (unless the user has logged out or the user session has expired).

Use this method to log in offline or call an Atlas Function upon subsequent app opens.

When your Realm application authenticates a user, it caches the user's credentials. You can check for existing user credentials to bypass the login flow and access the cached user. Use this to open a realm offline.

Note

Initial login requires a network connection

When a user signs up for your app, or logs in for the first time with an existing account on a client, the client must have a network connection. Checking for cached user credentials lets you open a realm offline, but only if the user has previously logged in while online.

// You can only open a synced realm offline if there is a cached user credential. If
// there is no app.currentUser, you must log them in, which requires a network connection.
if (app.currentUser == null) {
app.login(Credentials.emailPassword(email, password))
}
// If the app.currentUser isn't null, you can use the cached credential to open the synced
// realm even if the user is offline.
val user = app.currentUser!!
val realm = Realm.open(config)
// Query the realm we opened, and see that it contains data
val offlineToads: RealmResults<Toad> = realm.query<Toad>().find()
Log.v("After opening a realm offline, offlineToads.size is ${offlineToads.size}")
realm.close()

The Realm Kotlin SDK automatically manages access tokens, refreshes them when they expire, and includes a valid access token for the current user with each request. Tokens are removed after the user logs out.

Important

Realm only refreshes a user's access token. Realm does not automatically refresh the refresh token. When the refresh token expires, the SDK can no longer get an updated access token and the device cannot sync until the user logs in again.

For more information on user session access and refresh tokens, refer to User Sessions in the App Services documentation.

You can get the current access token for a logged-in user with the user.accessToken property:

val token = user.accessToken

If you send requests outside of the SDK, you must include the user's access token with each request and manually refresh the token when it expires. Access tokens expire 30 minutes after a user logs in.

You can get the current refresh token for a logged-in user with the user.refreshToken property, which you can use to request a new access token:

// Gets the current refresh token for the user
fun getRefreshToken(): String {
return user.refreshToken
}

Refresh tokens expire after a set period of time. When the refresh token expires, the access token can no longer be refreshed and the user must log in again.

If the refresh token expires after the realm is open, the device will not be able to sync until the user logs in again. Your sync error handler should implement logic that catches a token expired error when attempting to sync, then redirect users to a login flow.

For information on configuring refresh token expiration, refer to Manage User Sessions in the App Services documentation.

Warning

When a user logs out, you can no longer read or write data in any synced realms that the user opened. As a result, any operation that has not yet completed before the initiating user logs out cannot complete successfully and will likely result in an error. Any data in a write operation that fails in this way will be lost.

You can log out any user, regardless of the authentication provider used to log in, using user.logOut():

val app: App = App.create(YOUR_APP_ID) // Replace this with your App ID
runBlocking {
val user = app.login(credentials)
// ... work with logged-in user ...
// Ensure all local updates are uploaded
// before logging out
user.logOut()
}

The user.logOut() method:

  • Deletes locally stored user credentials from the device.

  • Immediately halts any synchronization to and from the user's realms.

  • For anonymous users, removes the user.

Because logging out halts synchronization, you should only log out after all local Realm updates have uploaded to the server.

New in version 10.8.0.

You can observe a flow of authentication change events by calling App.authenticationChangeAsFlow() . This flow emits AuthenticationChange events of three possible states, represented as subclasses:

  • LoggedIn: A user logs into the app.

  • LoggedOut: A a user logs out of the app.

  • Removed: A user is removed from the app, which also logs them out.

These events contain a user property that provides a reference to the User object that has logged in, logged out, or been removed.

// Create a Flow of AuthenticationChange objects
app.authenticationChangeAsFlow().collect {
change: AuthenticationChange ->
when (change) {
is LoggedIn -> proceedToAppActivity(change.user)
is LoggedOut -> proceedToLoginActivity(change.user)
is Removed -> proceedToRemovedUserActivity(change.user)
}
}

Back

Manage Users