Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/signing-sdk/face-auth-ios/llms.txt

Use this file to discover all available pages before exploring further.

The TAD Signing SDK is built around three complementary security mechanisms: face liveness detection to ensure a real user is present, WebAuthn passkeys stored in the device Secure Enclave for strong authentication, and ES512 (ECDSA P-521) signed JWTs for backend verification. Understanding how these layers interact helps you configure and deploy the SDK securely.

ES512 public key cryptography

The SDK verifies responses from the TAD backend using an ES512 public key — ECDSA using the P-521 curve and SHA-512. This key is provisioned by the backend team and supplied to the SDK through TadSigningConfig.publicKeyPem.
static let shared = TadSigningConfig(
    apiBaseUrl:   URL(string: "https://signing.tadi.uz")!,
    publicKeyPem: """
    -----BEGIN PUBLIC KEY-----
    MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQANTC0w0ACO79+hPYfK5fEF9nAAztI
    zpD8M0UTyR4ON5DeT3nKY12noi9PVVCIK1uwImeqsWx56cc7kMmWC99RKV0Az3JC
    Zq5gRExuUzk+aWcoG3DppFy2hCwEVeuDTENz0P5Rhx/BBJ8Q4jWVOM2AM2W3SQ/q
    1nG5s8ixxX2BnPBTQ7w=
    -----END PUBLIC KEY-----
    """,
    rpId:         "signing.tadi.uz",
    serviceName:  "tad-signing-demo",
    blockProxy:   true
)
Your backend must also hold this public key to verify the JWTs returned by the SDK’s .sign flow. The private key never leaves the TAD backend infrastructure; the SDK only receives and validates signed tokens.
The public key shown above is a demo key from the sample application. Never ship it in a production build. Request your production key from the TAD backend team and treat the SDKConfig.swift file as a secret — exclude it from source control or inject the key at build time via environment variables or a secrets manager.

Face liveness detection

During registration, the SDK captures video frames and runs an on-device liveness model to confirm that a real, live face is present. This prevents:
  • Photo attacks — holding a printed or displayed photograph in front of the camera.
  • Video replay attacks — playing a pre-recorded video of the target user.
  • 3D mask attacks — using a physical or digitally rendered mask.
The liveness check runs entirely before the passkey is created. If liveness fails, registration is rejected and no credential is stored. The NSCameraUsageDescription key in Info.plist is required because this step accesses the device camera.

WebAuthn/FIDO2 passkeys

Passkeys created during registration are FIDO2 WebAuthn credentials. They have several strong security properties:
  • Bound to rpId — a passkey created for signing.tadi.uz cannot be used on a different domain. Set rpId to your production domain and declare a matching webcredentials:<rpId> Associated Domains entitlement in your app.
  • Stored in Secure Enclave — the private key material is generated and stored in the device’s hardware security module. It cannot be extracted by software, including by your app or the SDK itself.
  • Protected by device biometrics — the OS requires Face ID, Touch ID, or device passcode before authorizing a passkey assertion, making silent credential use impossible.
  • Phishing-resistant — because credentials are scoped to the rpId domain, they cannot be used on lookalike sites or intercepted via phishing.
The Associated Domains entitlement must list your rpId:
<key>com.apple.developer.associated-domains</key>
<array>
    <string>webcredentials:signing.tadi.uz</string>
</array>
Your domain must serve an apple-app-site-association file at https://<rpId>/.well-known/apple-app-site-association that references your app’s bundle identifier (uz.tad.TadSigningDemo in the demo).

Proxy blocking

The blockProxy: true option in TadSigningConfig instructs the SDK to detect and reject connections that route through an HTTP/HTTPS proxy.
Proxy blocking prevents man-in-the-middle inspection of SDK network traffic. When blockProxy is true, the SDK will refuse to connect if it detects that a proxy is configured on the device — including debugging proxies such as Charles or mitmproxy. Set this to false only in development environments where you need to inspect traffic; always enable it in production builds.

OTP as an additional factor

The dto dictionary passed to TadSigningViewController can carry a one-time password as a second factor alongside the passkey:
let dto = otp.isEmpty ? [:] : ["otp": otp]
The backend validates the OTP independently of the passkey challenge. Using OTP adds a knowledge factor on top of the possession/biometric factors provided by the passkey, giving you MFA coverage for high-assurance signing operations.

Key rotation

The publicKeyPem in your TadSigningConfig must be updated whenever the TAD backend team rotates their signing key. Failing to update it will cause all JWT verifications to fail after rotation.
Treat key rotation as a planned maintenance event. Coordinate with your backend team to know the rotation schedule in advance. Consider injecting publicKeyPem from a remote configuration system (such as a feature flag service or a signed configuration endpoint) rather than hardcoding it, so you can update it without a full app release.
Rotation checklist:
  1. Obtain the new ES512 public key PEM from the backend team.
  2. Update publicKeyPem in your TadSigningConfig (or your remote config source).
  3. Update your backend JWT verification configuration with the same key.
  4. Test registration and signing end-to-end against the new key before the old key expires.
  5. Release the updated app and monitor for verification failures.

Summary of security properties

Face liveness

Prevents photo, video, and mask spoofing during registration. Requires camera access.

Secure Enclave passkeys

Private key never leaves the device hardware. Bound to your rpId domain.

ES512 JWT signing

ECDSA P-521 signatures on all SDK responses. Verify server-side before trusting claims.

Proxy blocking

Detects and rejects proxied connections to prevent MITM traffic inspection in production.

Build docs developers (and LLMs) love