Secure Connection Mode#
CloudXR Framework supports secure connections to CloudXR Runtime servers using TLS encryption and optional client token authentication. This document describes the available server configurations and how to connect securely from your client application.
Overview#
In secure connection mode, CloudXR Framework uses:
TLS/SSL encryption for the signaling connection
Client token authentication (optional) to verify the client’s identity with the server
Certificate validation to ensure the client is connecting to the intended server
Server Setup Options#
There are three ways to configure the server for secure connections:
Server Setup |
Description |
Connection Types |
Use Case |
|---|---|---|---|
Configure TLS directly using Runtime Management API properties ( |
|
Full control, custom deployments |
|
Run Runtime in non-secure mode behind an HTTPS reverse proxy with CA-signed certificate |
|
Cloud/production deployments |
|
Use Stream Manager to manage Runtime with auto-generated self-signed certificate |
|
Local/LAN development |
Option 1: Runtime API with TLS#
Configure TLS directly using the Runtime Management API. This gives you full control over certificate and authentication configuration.
Required properties:
certificate-pem: Path to your X.509 certificate filekey-pem: Path to your private key fileclient-token(optional): Preshared token for client authentication
Example using your own certificate:
// Set TLS certificate and key
nv_cxr_service_set_string_property(service, "certificate-pem", "/path/to/cert.pem");
nv_cxr_service_set_string_property(service, "key-pem", "/path/to/key.pem");
// Optionally set client token for authentication
nv_cxr_service_set_string_property(service, "client-token", "your-secret-token");
// Start the service
nv_cxr_service_start(service);
This approach works for both localSecure (with self-signed certificate and fingerprint validation) and remoteSecure (with CA-signed certificate and system trust validation) connection types.
Option 2: HTTPS Reverse Proxy#
Run CloudXR Runtime in non-secure mode (with no TLS configuration), and place an HTTPS reverse proxy in front of it. The proxy handles TLS termination using a CA-signed certificate.
This is the recommended approach for cloud and production deployments. Clients use a remoteSecure connection with system trust validation. No fingerprint distribution is required.
Architecture:
wss://cloudxr.example.com:48322 →ws://localhost:48010 →Requirements:
A public domain name (e.g.,
cloudxr.example.com)A CA-signed X.509 certificate from a trusted Certificate Authority
A reverse proxy (e.g., nginx, HAProxy) configured for WebSocket forwarding
Proxy configuration example (nginx):
server {
listen 48322 ssl;
server_name cloudxr.example.com;
ssl_certificate /etc/ssl/certs/cloudxr.example.com.crt;
ssl_certificate_key /etc/ssl/private/cloudxr.example.com.key;
location / {
proxy_pass http://localhost:48010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
Note
CloudXR.js uses a similar proxy approach for HTTPS hosting. Refer to WebSocket Proxy Setup for additional deployment examples including Docker and Kubernetes configurations.
Option 3: Stream Manager (Local Only)#
The Stream Manager automatically generates a self-signed certificate and manages client tokens. This is the simplest setup for local/LAN environments.
Important
Stream Manager uses a self-signed certificate, which requires fingerprint-based validation on the client. This only works with localSecure connections, and is not suitable for remote/cloud deployments.
Start the Stream Manager.
Enter this command:
NvStreamManager.exe
Set the client ID and get an auth token.
Enter this command at the Stream Manager’s command prompt (“>”):
SetClientId MyAVPClient
The Stream Manager displays this console output:
Setting client ID: MyAVPClient Client ID set successfully Token: <server_generated_auth_token>
Save the auth token for your client application.
Get the certificate fingerprint.
Enter this command at the Stream Manager’s command prompt:
GetCryptoKeyFingerprint 2
The Stream Manager displays this console output:
Getting cryptographic key fingerprint for algorithm: 2 Cryptographic key fingerprint: <fingerprint>
<fingerprint> is a 64-digit hexadecimal number. Share it with your client application through a trusted channel.
The parameter (‘2’ in the command above) specifies the hash algorithm:
0- MD51- SHA-12- SHA-256 (recommended)3- SHA-512
Start CloudXR Runtime.
Enter this command at the Stream Manager’s command prompt:
StartCxrService 6.0.0
The Stream Manager displays this console output:
Starting CloudXR service with version: 6.0.0 CloudXR service start request successful
Client Connection Types#
CloudXR Framework provides two secure connection types:
Local Secure Connection (localSecure): For LAN connections using self-signed certificates with fingerprint validation
Works with: Runtime API with TLS, Stream Manager
Certificate validation: Fingerprint-based
Use case: Development, testing, local deployments
Remote Secure Connection (remoteSecure): For cloud connections using CA-signed certificates with system trust validation
Works with: Runtime API with TLS, HTTPS Reverse Proxy
Certificate validation: System trust store
Use case: Cloud, production deployments
Configuring the Client#
Both connection types require a certificateValidationHandler callback that receives an URLAuthenticationChallenge and returns a tuple of URLSession.AuthChallengeDisposition and optional URLCredential.
Local Secure Connection#
Use ConnectionType.localSecure for secure connections using self-signed certificates (with Runtime API or Stream Manager). This requires fingerprint-based certificate validation:
import CloudXRKit
import CryptoKit
import Security
// The client token obtained from server
let clientToken = "AUTH_TOKEN_GENERATED_BY_SERVER"
// The expected certificate fingerprint (SHA-256)
let expectedFingerprint = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
var config = CloudXRKit.Config()
config.connectionType = .localSecure(
ip: "192.168.1.100",
clientToken: clientToken,
certificateValidationHandler: { challenge in
// Validate using fingerprint for self-signed certificates
guard let serverTrust = challenge.protectionSpace.serverTrust,
let certificateChain = SecTrustCopyCertificateChain(serverTrust),
CFArrayGetCount(certificateChain) > 0 else {
return (.cancelAuthenticationChallenge, nil)
}
let certificate = unsafeBitCast(
CFArrayGetValueAtIndex(certificateChain, 0),
to: SecCertificate.self
)
let certificateData = SecCertificateCopyData(certificate) as Data
let fingerprint = SHA256.hash(data: certificateData)
.map { String(format: "%02x", $0) }
.joined()
if fingerprint.lowercased() == expectedFingerprint.lowercased() {
return (.useCredential, URLCredential(trust: serverTrust))
} else {
return (.cancelAuthenticationChallenge, nil)
}
}
)
cxrSession.configure(config: config)
try await cxrSession.connect()
Remote Secure Connection#
Use ConnectionType.remoteSecure for secure connections using CA-signed certificates (with Runtime API or HTTPS Reverse Proxy). This uses the operating system’s certificate trust store:
import CloudXRKit
var config = CloudXRKit.Config()
config.connectionType = .remoteSecure(
host: "cloudxr.example.com", // Your public domain with CA-signed certificate
signalingHeaders: [
"Authorization": "Bearer your-auth-token",
"X-Custom-Header": "custom-value"
],
certificateValidationHandler: { challenge in
// Validate using system trust store for CA-signed certificates
guard let serverTrust = challenge.protectionSpace.serverTrust else {
return (.cancelAuthenticationChallenge, nil)
}
var error: CFError?
if SecTrustEvaluateWithError(serverTrust, &error) {
return (.useCredential, URLCredential(trust: serverTrust))
} else {
return (.cancelAuthenticationChallenge, nil)
}
}
)
cxrSession.configure(config: config)
try await cxrSession.connect()
Trust All Certificates (Development Only)#
Warning
Use this approach only during development and testing. Never use it in production.
certificateValidationHandler: { challenge in
guard let serverTrust = challenge.protectionSpace.serverTrust else {
return (.cancelAuthenticationChallenge, nil)
}
return (.useCredential, URLCredential(trust: serverTrust))
}
Session States#
When using secure connection mode, the session transitions through additional authentication states:
initialized: The initial state
authenticating: Validating credentials with server
authenticated: Credentials validated successfully
connecting: Establishing streaming connection
connected: Streaming active
You can monitor these states:
switch cxrSession.state {
case .initialized:
print("Ready to connect")
case .authenticating:
print("Validating credentials...")
case .authenticated:
print("Credentials validated")
case .connecting:
print("Establishing stream...")
case .connected:
print("Streaming!")
case .disconnected(let result):
switch result {
case .success:
print("Disconnected normally")
case .failure(let error):
print("Error: \(error)")
}
default:
break
}
Error Handling#
Secure connections can fail due to:
Invalid client token: The token doesn’t match the server’s expected value.
Certificate validation failure: The certificate fingerprint doesn’t match.
Network errors: The client is unable to reach the server.
TLS handshake failure: TLS versions or cipher suites are incompatible.
Handle these errors appropriately:
do {
try await cxrSession.connect()
} catch let error as StreamingError {
switch error {
case .connectionFailed:
print("Failed to connect - check server address and token")
case .authenticationFailed:
print("Authentication failed - verify client token")
default:
print("Streaming error: \(error)")
}
} catch {
print("Unexpected error: \(error)")
}
Best Practices#
For Local Secure Connections (LAN/Development):
Store credentials securely: Use
Keychainto store client tokens, notUserDefaults.Use SHA-256 fingerprints: SHA-256 provides strong security without being too cumbersome.
Distribute fingerprints securely: Share certificate fingerprints through a trusted channel, not over the network.
Rotate tokens periodically: Generate new client tokens for each session or deployment.
Use Stream Manager: Stream Manager simplifies certificate and token management for local deployments.
For Remote Secure Connections (Cloud/Production):
Use CA-signed certificates: Deploy with certificates from a trusted Certificate Authority.
Use HTTPS reverse proxy: HTTPS reverse proxy handles TLS termination centrally, and is recommended for cloud deployments.
Use a public domain: Configure a proper domain name for your streaming endpoint.
Use system trust validation: Leverage the OS certificate trust store instead of using fingerprint pinning.
General:
Handle authentication states: Show appropriate information in the UI during the authentication phase.
Implement proper error handling: Provide clear feedback for authentication and certificate errors.
Network Requirements#
Secure connections use the following ports:
TCP 48322: Secure a signaling connection (TLS). It replaces port 48010 used in standard mode.
UDP 47998-48002, 48005, 48008, and 48012: Use for media streaming (video, input, and audio).
Note
When using secure connection mode, port 48010 is not used. All signaling traffic goes through port 48322 with TLS encryption.
Ensure that these ports are open in your firewall. Refer to Network Setup for complete network configuration.
Troubleshooting#
Connection fails with “authentication failed”:
Verify that the client token matches the server’s configured value.
Ensure that Stream Manager is running before starting the CloudXR service.
For the Runtime API, verify that the
client-tokenproperty is set correctly.Check that the token is transmitted correctly, with no extra whitespace or encoding issues.
Certificate validation fails:
For fingerprint validation: - Verify that the client’s fingerprint was copied correctly, with no extra whitespace.
Ensure that you’re using the same hash algorithm on client and server (SHA-256 recommended).
Ensure that the server certificate was regenerated (get new fingerprint).
For system trust validation: - Verify that the server’s CA-signed certificate is valid and not expired. - Ensure that the certificate chain is complete.
TLS handshake fails:
Verify that the server supports TLS 1.2 or later/
Check that the server logs for TLS-related errors.
Ensure that the firewall allows TLS traffic on port 48322.
For Runtime API: Verify that certificate and key file paths are correct and readable.
See Also#
Your First CloudXR Client for visionOS - Basic CloudXR Framework setup
CloudXR Runtime Management API - Runtime Management API with TLS properties
Stream Manager - Stream Manager for local secure connections
WebSocket Proxy Setup - HTTPS reverse proxy setup examples
Network Setup - Network configuration and firewall requirements