Skip to main content

Server config

The duo example talks to a Duo server over two channels: a websocket for MPC protocol messages (handled by the SDK) and HTTP for fetching the server party's encrypted keyshare during export and for verifiable-backup verification (handled by the app). By default both point at the same public demo host:

PurposeDefault value
MPC websocket (WebsocketConfig.url)demo-server.silencelaboratories.com (port 443, TLS)
Cloud verifying keycfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4
Server HTTP APIhttps://demo-server.silencelaboratories.com

You'll typically swap these for one of three reasons: pointing at your own dev server, running locally for hacking, or moving to a production deployment of your own.

Where the values live

The websocket URL, port, and cloud verifying key are defined in VaultSessionManager — the SDK handles MPC transport and session authentication internally. The server HTTP endpoint is in AppConstants.

vault/.../session/VaultSessionManager.kt
companion object {
private const val DEMO_SERVER_URL = "demo-server.silencelaboratories.com"
private const val DEMO_SERVER_PORT = 443
private const val CLOUD_VERIFYING_KEY =
"cfa1ff5424d14eb60614d7ddf65a32243d26ddf7000d10007853d7336395efe4"
}

private val websocketConfig = WebsocketConfig(
url = DEMO_SERVER_URL,
port = DEMO_SERVER_PORT,
isSecure = true,
)
app/.../util/Constants.kt
object AppConstants {
const val DEMO_SERVER_HTTP_URL = "https://demo-server.silencelaboratories.com" // used by ExportImportViewModel
// ...
}

Configuring the WebsocketConfig endpoint

WebsocketConfig accepts the MPC endpoint two ways — the demo config above uses the host-plus-parts form so the TLS scheme is explicit:

// Full URL — used verbatim; port and isSecure are ignored.
WebsocketConfig(url = "wss://your-server.com")

// Host + parts — the scheme and port are composed from isSecure and port.
WebsocketConfig(url = "your-server.com", port = 443, isSecure = true) // -> wss://your-server.com:443
WebsocketConfig(url = "10.0.2.2", port = 8080, isSecure = false) // -> ws://10.0.2.2:8080 (local dev)

// Optional token, sent as the first message once connected (e.g. a JWT).
WebsocketConfig(url = "wss://your-server.com", authenticationToken = "<jwt>")

port and isSecure (default true) apply only when url has no scheme; a full ws:///wss:// URL is used as-is. The SDK derives the HTTP endpoint for POST-based steps from the same fields.

Pointing at a local Duo server

You'll need a local Duo server first. The simplest path is the Docker setup in the Kotlin Quick Start under "Optional: Run your own Duo Server" — it walks through docker pull, the docker-compose.yml, and finding the cloud verifying key in the server logs.

Once your server is running, change three things in the example:

  1. Vault websocket URL (VaultSessionManager.<DEMO_SERVER_URL|demoServerUrl>) — point at your local server and set isSecure = false for a plaintext ws:// connection.
  2. Cloud verifying key (VaultSessionManager.<CLOUD_VERIFYING_KEY|cloudVerifyingKey>) — copy the hex string the local server prints on startup (Party VK <hex>). The handshake fails silently if this doesn't match.
  3. Backup HTTP URL (AppConstants.DEMO_SERVER_HTTP_URL) — change https://… to http://… (unless your local server terminates TLS).

The Android emulator routes localhost to the emulator itself, so use 10.0.2.2 to reach a server on your host machine:

vault/.../session/VaultSessionManager.kt
private const val DEMO_SERVER_URL = "10.0.2.2"
private const val DEMO_SERVER_PORT = 8080
private const val CLOUD_VERIFYING_KEY = "<hex from local server logs>"
// ...
private val websocketConfig = WebsocketConfig(url = DEMO_SERVER_URL, port = DEMO_SERVER_PORT, isSecure = false)
app/.../util/Constants.kt
const val DEMO_SERVER_HTTP_URL = "http://10.0.2.2:8080"

For cleartext HTTP, the demo's network_security_config.xml may need to allow 10.0.2.2 — otherwise ExportImportViewModel fails the backup fetch with CLEARTEXT communication not permitted. Add a <domain-config> exception, or set android:usesCleartextTraffic="true" in the manifest for testing.