Skip to main content

Usage

All four verbs are async. connect() and disconnect() can throw a WiDASError; status() never does.

Configure

Create one WiDAS instance and hold onto it wherever your app keeps long-lived services. It ships no secret, so there's nothing sensitive to protect here.

import WiDAS

let widas = WiDAS(
clientId: "client-acme",
keychainAccessGroup: "<TeamID>.com.apple.networkextensionsharing"
)
ParameterRequiredNotes
clientIdYour Wi-DAS-issued public client identifier.
keychainAccessGrouprecommendedShared group so the NetworkExtension can pair the client identity. nil uses the app default.

Connect

connect() is idempotent. Call it on launch, and again after any expired or revoked status. requestedValidity is an ISO-8601 duration; Wi-DAS clamps it to policy.

do {
let result = try await widas.connect(user: "user-42", requestedValidity: "P365D")
print("Onboarded. Serial \(result.serial), expires \(result.notAfter)")
} catch let error as WiDASError {
handle(error) // see Error handling
}

ConnectionResult carries the certificate serial and its notAfter expiry.

What idempotent buys you

The first connect() on a device registers a fresh App Attest key; every later call asserts the one it already has. You don't manage that split. You always just call connect(user:…).

Status

status() is advisory and never throws, so it's safe to call whenever you're rendering UI.

let status = await widas.status()
switch status.state {
case .none:
promptToConnect() // nothing installed yet
case .valid:
showConnected(expiry: status.expiry)
case .expired, .revoked:
try? await widas.connect(user: "user-42", requestedValidity: "P365D") // re-onboard
}

Status gives you state (.none/.valid/.expired/.revoked), the serial, and the expiry. Remember the network is the real authority here; status() is for the UI.

Disconnect

Remove the installed profile when the user asks, or after a revoked result.

try await widas.disconnect()

The attested App Attest key sticks around, so a later connect() takes the fast assertion path.

A complete launch flow

func onLaunch(userID: String) async {
do {
// Idempotent: first run, renewal or recovery — one call.
_ = try await widas.connect(user: userID, requestedValidity: "P365D")
} catch WiDASError.attestationUnavailable {
showUnsupported() // e.g. Simulator, or App Attest unsupported
} catch let error as WiDASError {
handle(error)
} catch {
// Cancellation / unexpected.
}

render(await widas.status()) // reflect real state in the UI
}
Keep connect() off the main actor

connect() does key generation, attestation, and network I/O. Run it from a background task and update your UI on the main actor once you have the result.

Next: Error handling.