Add KDoc to matrix API authentication and device linking interfaces

Document MatrixAuthenticationService, OAuthRedirectUrlProvider, the two QR code
login data interfaces, and the four device linking interfaces, along with their
members and parameters.

The docs record the ordering constraints a caller has to respect: setHomeserver
must precede any login attempt, the link handlers report their outcome through
their step flow rather than through a return value, and ContinuationMessageSender
expects exactly one of cancel or confirm.

The oauth package holds only a sealed interface, so it is out of scope here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benoit Marty
2026-08-13 19:14:00 +02:00
parent fa01166197
commit 0b2d6eafc3
8 changed files with 92 additions and 1 deletions
@@ -16,23 +16,41 @@ import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeLoginStep
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
/**
* Creates and restores sessions: password login, OAuth login, QR code login, and importing a session from another client.
*
* [setHomeserver] must be called before any login attempt, since it is what tells the SDK which server to authenticate against.
* Every successful login stores the session and notifies the listeners registered through [listenToNewMatrixClients].
*/
interface MatrixAuthenticationService { interface MatrixAuthenticationService {
/** /**
* Restore a session from a [sessionId]. * Restore a session from a [sessionId].
* Do not restore anything it the access token is not valid anymore. * Do not restore anything it the access token is not valid anymore.
* Generally this method should not be used directly, prefer using [MatrixClientProvider.getOrRestore] instead. * Generally this method should not be used directly, prefer using [MatrixClientProvider.getOrRestore] instead.
*
* @param sessionId the session to restore.
*/ */
suspend fun restoreSession(sessionId: SessionId): Result<MatrixClient> suspend fun restoreSession(sessionId: SessionId): Result<MatrixClient>
/** /**
* Set the homeserver to use for authentication, and return its details. * Set the homeserver to use for authentication, and return its details.
*
* @param homeserver the homeserver URL or server name to authenticate against.
*/ */
suspend fun setHomeserver(homeserver: String): Result<MatrixHomeServerDetails> suspend fun setHomeserver(homeserver: String): Result<MatrixHomeServerDetails>
/**
* Logs in with a password on the homeserver previously set through [setHomeserver].
*
* @param username the user id or its local part.
* @param password the account password.
*/
suspend fun login(username: String, password: String): Result<SessionId> suspend fun login(username: String, password: String): Result<SessionId>
/** /**
* Import a session that was created using another client, for instance Element Web. * Import a session that was created using another client, for instance Element Web.
*
* @param externalSession the tokens and identifiers of the session to import.
*/ */
suspend fun importCreatedSession(externalSession: ExternalSession): Result<SessionId> suspend fun importCreatedSession(externalSession: ExternalSession): Result<SessionId>
@@ -42,6 +60,9 @@ interface MatrixAuthenticationService {
/** /**
* Get the OAuth url to display to the user. * Get the OAuth url to display to the user.
*
* @param prompt whether the authentication server should show the sign-in or the account-creation page.
* @param loginHint the user identifier to pre-fill on that page, or `null` to leave it empty.
*/ */
suspend fun getOAuthUrl( suspend fun getOAuthUrl(
prompt: OAuthPrompt, prompt: OAuthPrompt,
@@ -55,11 +76,17 @@ interface MatrixAuthenticationService {
/** /**
* Set the existing data about Element Classic session, if any. * Set the existing data about Element Classic session, if any.
*
* @param session the session found in a local Element Classic install, or `null` when there is none to migrate.
*/ */
fun setElementClassicSession(session: ElementClassicSession?) fun setElementClassicSession(session: ElementClassicSession?)
/** /**
* Check if the provided secrets from Element Classic session contain a key backup. * Check if the provided secrets from Element Classic session contain a key backup.
*
* @param userId the user the secrets belong to.
* @param secrets the raw secrets exported from Element Classic.
* @param backupInfo the raw backup description exported alongside them.
*/ */
fun doSecretsContainBackupKey( fun doSecretsContainBackupKey(
userId: UserId, userId: UserId,
@@ -69,11 +96,23 @@ interface MatrixAuthenticationService {
/** /**
* Attempt to log in using the [callbackUrl] provided by the OAuth page. * Attempt to log in using the [callbackUrl] provided by the OAuth page.
*
* @param callbackUrl the redirect URL the authentication server sent the user back to, carrying the authorization code.
*/ */
suspend fun loginWithOAuth(callbackUrl: String): Result<SessionId> suspend fun loginWithOAuth(callbackUrl: String): Result<SessionId>
/**
* Logs in by acting on a QR code shown by an already signed in device, reporting each step of the exchange as it happens.
*
* @param qrCodeData the decoded QR code, obtained from [io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginDataFactory].
* @param progress called on every step of the flow, so the UI can follow along.
*/
suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit): Result<SessionId> suspend fun loginWithQrCode(qrCodeData: MatrixQrCodeLoginData, progress: (QrCodeLoginStep) -> Unit): Result<SessionId>
/** Listen to new Matrix clients being created on authentication. */ /**
* Listen to new Matrix clients being created on authentication.
*
* @param lambda called with each client created by a successful login or session restore.
*/
fun listenToNewMatrixClients(lambda: (MatrixClient) -> Unit) fun listenToNewMatrixClients(lambda: (MatrixClient) -> Unit)
} }
@@ -8,6 +8,10 @@
package io.element.android.libraries.matrix.api.auth package io.element.android.libraries.matrix.api.auth
/**
* Provides the redirect URL registered for OAuth login, which the authentication server sends the user back to once they have signed in.
*/
interface OAuthRedirectUrlProvider { interface OAuthRedirectUrlProvider {
/** Returns the redirect URL, built from the app's custom URL scheme so that the system hands the callback back to the app. */
fun provide(): String fun provide(): String
} }
@@ -8,6 +8,12 @@
package io.element.android.libraries.matrix.api.auth.qrlogin package io.element.android.libraries.matrix.api.auth.qrlogin
/**
* The decoded content of a login QR code, as produced by [MatrixQrCodeLoginDataFactory].
*
* The underlying data is opaque to the app: it is passed back to the SDK to perform the login.
*/
interface MatrixQrCodeLoginData { interface MatrixQrCodeLoginData {
/** The homeserver advertised by the QR code, or `null` when it does not carry one. */
fun serverName(): String? fun serverName(): String?
} }
@@ -8,6 +8,14 @@
package io.element.android.libraries.matrix.api.auth.qrlogin package io.element.android.libraries.matrix.api.auth.qrlogin
/**
* Decodes the raw bytes of a scanned QR code into login data the SDK can use.
*/
interface MatrixQrCodeLoginDataFactory { interface MatrixQrCodeLoginDataFactory {
/**
* Parses the scanned bytes, failing with a [QrCodeDecodeException] when they are not a valid Matrix login QR code.
*
* @param data the raw content read from the QR code.
*/
fun parseQrCodeData(data: ByteArray): Result<MatrixQrCodeLoginData> fun parseQrCodeData(data: ByteArray): Result<MatrixQrCodeLoginData>
} }
@@ -7,6 +7,9 @@
package io.element.android.libraries.matrix.api.linknewdevice package io.element.android.libraries.matrix.api.linknewdevice
/**
* Lets the user confirm the two-digit check code displayed by the device being linked, which proves the channel is not being intercepted.
*/
interface CheckCodeSender { interface CheckCodeSender {
/** /**
* Validates the given [code]. Returns true if the code is valid, false otherwise. * Validates the given [code]. Returns true if the code is valid, false otherwise.
@@ -7,7 +7,15 @@
package io.element.android.libraries.matrix.api.linknewdevice package io.element.android.libraries.matrix.api.linknewdevice
/**
* Lets the user confirm or refuse a device linking request once they have approved it in the browser.
*
* Handed out with the step that is waiting for authorisation; exactly one of the two methods is meant to be called.
*/
interface ContinuationMessageSender { interface ContinuationMessageSender {
/** Tells the other device that the user refused the linking, which ends the flow. */
suspend fun cancel(): Result<Unit> suspend fun cancel(): Result<Unit>
/** Tells the other device that the user approved the linking, so the flow can carry on. */
suspend fun confirm(): Result<Unit> suspend fun confirm(): Result<Unit>
} }
@@ -10,8 +10,22 @@ package io.element.android.libraries.matrix.api.linknewdevice
import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeDecodeException import io.element.android.libraries.matrix.api.auth.qrlogin.QrCodeDecodeException
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
/**
* Drives the linking of a new device that cannot scan a QR code, such as a desktop: this device scans the code the other one displays.
*
* Progress is reported entirely through [linkDesktopStep]; there is one handler per attempt, obtained from
* [io.element.android.libraries.matrix.api.MatrixClient.createLinkDesktopHandler].
*/
interface LinkDesktopHandler { interface LinkDesktopHandler {
/** Each step of the flow, from establishing the secure channel to syncing the secrets to the new device. */
val linkDesktopStep: StateFlow<LinkDesktopStep> val linkDesktopStep: StateFlow<LinkDesktopStep>
/**
* Runs the whole flow from the QR code just scanned, suspending until it finishes or fails.
* A code that cannot be decoded is reported as an invalid-QR-code step rather than as a thrown error.
*
* @param data the raw content read from the QR code shown by the other device.
*/
suspend fun handleScannedQrCode(data: ByteArray) suspend fun handleScannedQrCode(data: ByteArray)
} }
@@ -9,8 +9,17 @@ package io.element.android.libraries.matrix.api.linknewdevice
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/**
* Drives the linking of a new device that is able to scan a QR code, by showing one on this already signed in device.
*
* Progress is reported entirely through [linkMobileStep]; there is one handler per attempt, obtained from
* [io.element.android.libraries.matrix.api.MatrixClient.createLinkMobileHandler].
*/
interface LinkMobileHandler { interface LinkMobileHandler {
/** Each step of the flow, from generating the QR code to syncing the secrets to the new device. */
val linkMobileStep: Flow<LinkMobileStep> val linkMobileStep: Flow<LinkMobileStep>
/** Runs the whole flow, suspending until it finishes or fails; the outcome is reported through [linkMobileStep]. */
suspend fun start() suspend fun start()
} }