/** * Hawcx Auth Protocol v2 Type Definitions * * Source of truth for wire request/response shapes. * Generate Swift/Kotlin/Dart types from this file. * * @version 2.0.0 */ export declare const PROTOCOL_VERSION: 2; export declare const SUPPORTED_ALGORITHMS: readonly ["Ed25519"]; /** * Crypto versions this SDK supports for device enrollment. * Server picks the best mutual version (newest first). */ export declare const SUPPORTED_CRYPTO_VERSIONS: readonly ["zkp_v1"]; /** @deprecated Use SUPPORTED_CRYPTO_VERSIONS instead */ export declare const SUPPORTED_SETUP_VERSION: "zkp_v1"; export interface WireRequest { protocolVersion: typeof PROTOCOL_VERSION; session?: string; action: Action; } export interface WireResponse { protocolVersion: typeof PROTOCOL_VERSION; session: string; /** The current auth step for the client to render or handle */ step: AuthStep; meta: ResponseMeta; } export interface ResponseMeta { /** Unique request identifier for tracing */ traceId: string; /** Session expiration (ISO 8601) */ expiresAt: string; } export type Action = StartAction | SelectMethodAction | SubmitCodeAction | SubmitTotpAction | SubmitPhoneAction | RequestChallengeAction | SubmitSignatureAction | OAuthCallbackAction | ResendAction | PollAction | CancelAction; export interface StartAction { type: "start"; /** Auth mode: "signin", "signup", "account_manage" */ flowType: string; identifier: string; /** Required for some flows (e.g., step-up auth) */ startToken?: string; /** Optional device fingerprinting data */ device?: DeviceInfo; /** Device credentials for automatic device trust verification (SDK sends if available) */ deviceCredentials?: DeviceCredentials; /** * Crypto versions this SDK supports for device enrollment/verification. * Sent on every flow start so the server can negotiate the best mutual version. * Example: ["zkp_v1"] */ cryptoVersions?: readonly string[] | string[]; /** * PKCE code_challenge (S256 method). * SDK generates a random code_verifier at flow start, computes SHA256 hash, * and sends the base64url-encoded hash here. The verifier is held locally * until completion, then combined with authCode for token exchange. */ codeChallenge?: string; } /** * Stored device credentials for device trust verification at flow start. * SDK loads these from IndexedDB and sends them automatically for signin flows. */ export interface DeviceCredentials { /** Base64-encoded encrypted keyset containing public/private key pair */ keyset: string; /** Base64-encoded hash index for device lookup */ hindex: string; /** Base64-encoded secret key used to decrypt keyset */ sk2: string; } export interface DeviceInfo { /** Schema version for handling different DeviceInfo formats from different SDK versions */ v: 1; /** SDK-computed fingerprint hash - the primary device identifier */ fingerprint: string; /** All other device data (userAgent, os, timezone, screen, locale, etc.) */ signals?: Record; } export interface SelectMethodAction { type: "select_method"; methodName: string; } export interface SubmitCodeAction { type: "submit_code"; code: string; } export interface SubmitTotpAction { type: "submit_totp"; /** 6-digit TOTP code or XXXX-XXXX backup code */ code: string; } export interface SubmitPhoneAction { type: "submit_phone"; /** Phone number in E.164 format (e.g., "+1234567890") */ phone: string; } /** * Request a device challenge from the server. * * SDK-INTERNAL: Used during device enrollment to send the generated keyset * to the server and receive a challenge to sign. This action is sent * automatically by the SDK after receiving a setup_device step. */ export interface RequestChallengeAction { type: "request_challenge"; /** Base64-encoded encrypted keyset containing the public key */ keyset: string; /** Base64-encoded hash index for key lookup */ hindex: string; /** Base64-encoded SK2 for keyset decryption */ sk2: string; } export interface SubmitSignatureAction { type: "submit_signature"; keyId: string; signature: string; mapp: string; } export interface OAuthCallbackAction { type: "oauth_callback"; code: string; state: string; } export interface ResendAction { type: "resend"; } export interface PollAction { type: "poll"; } export interface CancelAction { type: "cancel"; } export type AuthStep = SelectMethodStep | EnterCodeStep | EnterTotpStep | SetupTotpStep | SetupSmsStep | SetupDeviceStep | DeviceChallengeStep | RedirectStep | AwaitApprovalStep | CompletedStep | ErrorStep; export interface SelectMethodStep { type: "select_method"; /** Current phase: "primary", "mfa", or "enrollment" */ phase: "primary" | "mfa" | "enrollment"; methods: Method[]; } export interface EnterCodeStep { type: "enter_code"; /** Masked destination. Example: "s***@example.com" or "+1***7890" */ destination: string; /** Delivery channel: how the code was sent. Optional for backwards compatibility. */ channel?: "sms" | "email"; /** Expected code length */ codeLength: number; /** Code format for keyboard hints */ codeFormat: "numeric" | "alphanumeric"; /** When code expires (ISO 8601) */ codeExpiresAt: string; /** When resend is available (ISO 8601) */ resendAt: string; } export interface EnterTotpStep { type: "enter_totp"; } export interface SetupTotpStep { type: "setup_totp"; /** Base32-encoded TOTP secret */ secret: string; /** otpauth:// URL for QR code generation */ otpauthUrl: string; /** TOTP period in seconds (typically 30) */ period: number; /** One-time recovery codes (XXXX-XXXX format). Show once during enrollment. */ backupCodes?: string[]; } /** * SMS enrollment step. * * Shown when user needs to provide a phone number for SMS OTP. * Client should display phone input field. */ export interface SetupSmsStep { type: "setup_sms"; /** Optional: existing masked phone to replace */ existingPhone?: string; } /** * Device enrollment step. * * SDK-INTERNAL: This step is handled automatically by SDKs and MUST NOT be * rendered to users. When received, SDKs should: * 1. Generate an Ed25519 keypair * 2. Store the keypair securely (IndexedDB/Keychain) * 3. Build the encrypted keyset with hindex * 4. Send a request_challenge action with the keyset * * This step is returned during the enrollment phase when no device key * exists yet (signup or first signin on new device). */ export interface SetupDeviceStep { type: "setup_device"; /** Domain for key binding */ domain: string; /** Algorithm for key generation */ algorithm: "Ed25519"; /** Version of the enrollment protocol */ version: string; } /** * Device verification challenge. * * SDK-INTERNAL: This step is handled automatically by SDKs and MUST NOT be * rendered to users. SDKs intercept this step, load the private key from * secure storage, sign the challenge, and submit automatically. * * This step may be returned immediately after `start` when device trust is * enabled and the device is recognized. */ export interface DeviceChallengeStep { type: "device_challenge"; /** Challenge bytes to sign */ challenge: string; /** Encoding of challenge */ challengeEncoding: "base64"; /** Key ID to use for signing */ keyId: string; /** Signature algorithm */ algorithm: "Ed25519"; /** Domain for signature binding */ domain: string; /** Base64-encoded combinedsalt for key unwrap */ combinedsalt: string; /** Expected response encoding */ responseEncoding: "base64"; } export interface RedirectStep { type: "redirect"; /** Full redirect URL */ url: string; /** Deep link scheme for mobile */ returnScheme?: string; } export interface AwaitApprovalStep { type: "await_approval"; /** QR code data (optional) */ qrData?: string; /** When approval expires (ISO 8601) */ expiresAt: string; /** Suggested poll interval in seconds */ pollInterval: number; } export interface CompletedStep { type: "completed"; /** Authorization code */ authCode: string; /** When auth code expires (ISO 8601) */ expiresAt: string; } /** * Server-driven error actions. * * These tell the client what to do. Keep this set small and stable. * Unknown actions from newer servers should fall back to showing the message. */ export type ErrorAction = "retry_input" | "restart_flow" | "wait" | "retry_request" | "abort" | "resend_code" | "select_method"; /** * Error step with server-driven action. * * @example * ```typescript * if (isErrorStep(step)) { * switch (step.action) { * case "retry_input": * showError(step.message); * focusInput(); * break; * case "wait": * await delay(step.details.retry_after_seconds * 1000); * retry(); * break; * case "restart_flow": * auth.reset(); * navigate("/auth"); * break; * default: * // Unknown action from newer server * showError(step.message); * } * } * ``` */ export interface ErrorStep { type: "error"; /** Machine-readable error code (for logging, not branching) */ code: string; /** Server-driven action - BRANCH ON THIS */ action: ErrorAction | (string & {}); /** Human-readable message */ message: string; /** Whether user can retry */ retryable: boolean; /** Additional error details (varies by action) */ details?: ErrorDetails; } /** * Error details - varies by action. * * - `wait` action requires `retry_after_seconds` * - Other actions may have additional context */ export interface ErrorDetails { /** Seconds to wait before retry (for "wait" action) */ retry_after_seconds?: number; /** Validation errors (for validation failures) */ errors?: Array<{ field: string; message: string; }>; /** Any additional context */ [key: string]: unknown; } export interface Method { /** Unique method name/identifier */ name: string; /** Human-readable label */ label: string; /** Icon identifier (optional) */ icon?: string; } export declare function isSelectMethodStep(s: AuthStep): s is SelectMethodStep; export declare function isEnterCodeStep(s: AuthStep): s is EnterCodeStep; export declare function isEnterTotpStep(s: AuthStep): s is EnterTotpStep; export declare function isSetupTotpStep(s: AuthStep): s is SetupTotpStep; export declare function isSetupSmsStep(s: AuthStep): s is SetupSmsStep; export declare function isSetupDeviceStep(s: AuthStep): s is SetupDeviceStep; export declare function isDeviceChallengeStep(s: AuthStep): s is DeviceChallengeStep; export declare function isRedirectStep(s: AuthStep): s is RedirectStep; export declare function isAwaitApprovalStep(s: AuthStep): s is AwaitApprovalStep; export declare function isCompletedStep(s: AuthStep): s is CompletedStep; export declare function isErrorStep(s: AuthStep): s is ErrorStep; /** Extract action type for type narrowing */ export type ActionType = Action["type"]; /** Extract step type for type narrowing */ export type StepType = AuthStep["type"]; /** Get step by type */ export type StepByType = Extract; /** Get action by type */ export type ActionByType = Extract;