Skip to content

Mobile Onboarding

Create an Auths identity on an iOS device and register it with a server.

Architecture

sequenceDiagram
    participant App as iOS App
    participant Server

    App->>App: createIdentity()<br/>keypairs + inception event

    App->>Server: POST /register<br/>(inception event)
    Server->>Server: Validate inception event
    Server->>Server: Store DID + public key
    Server-->>App: 200 OK

    App->>App: Store keys in iOS Keychain

    App->>App: signWithIdentity(data)<br/>→ signature

    App->>Server: POST /api<br/>(data + signature)
    Server->>Server: verifyAttestation()
    Server->>Server: Process request
    Server-->>App: 200 OK

iOS implementation

import AuthsMobile

class OnboardingService {
    func createAccount() async throws -> String {
        // 1. Create identity on-device
        let identity = try createIdentity(deviceName: UIDevice.current.name)

        // 2. Store keys in iOS Keychain
        try KeychainService.save(
            key: identity.currentKeyPkcs8Hex,
            forKey: "auths-current-key"
        )
        try KeychainService.save(
            key: identity.nextKeyPkcs8Hex,
            forKey: "auths-next-key"
        )

        // 3. Register with server
        let response = try await API.post("/register", body: [
            "prefix": identity.prefix,
            "did": identity.did,
            "public_key_hex": identity.currentPublicKeyHex,
            "inception_event": identity.inceptionEventJson
        ])

        return identity.did
    }
}

Server-side validation

from auths_verifier import verify_attestation

@app.route("/register", methods=["POST"])
def register():
    data = request.json
    inception = data["inception_event"]
    pk_hex = data["public_key_hex"]

    # Validate the inception event is self-consistent
    # (signed by the key it claims to represent)
    result = verify_attestation(inception, pk_hex)
    if not result.valid:
        return jsonify({"error": "Invalid inception event"}), 400

    # Store the identity
    db.save_identity(
        did=data["did"],
        public_key=pk_hex,
        prefix=data["prefix"]
    )

    return jsonify({"status": "registered"})

Security considerations

  • Keys are generated using ring::rand::SystemRandom (cryptographically secure)
  • Private keys never leave the device (stored in iOS Keychain)
  • Inception events are self-authenticating (signed by the key they contain)
  • The server should validate the inception event before trusting the identity