Skip to main content

Overview

Hawcx SDK delivers revolutionary Smart Connect technology - the most intuitive passwordless authentication ever created for Android applications. Smart Connect intelligently handles both sign up and sign in through a single, unified interface, eliminating decision fatigue while maintaining enterprise-grade security.

Smart Connect Technology

One-click intelligent authentication that automatically determines user context

Contextual Intelligence

No more “Sign Up” vs “Sign In” confusion - just one smart entry point

Seamless Cross-Platform

Smart Connect maintains user context across all devices and platforms

Web Login Approval

Allow users to approve web logins from their mobile device

Enterprise-Grade Security

Revolutionary security with consumer-grade simplicity

Architecture

Quick Start

1

Installation

  • Gradle
  • Kotlin DSL
  • Manual
dependencies {
    implementation 'com.hawcx:hawcx-android-sdk:4.0.0'
}
2

Initialize SDK

import com.hawcx.internal.HawcxSDK

class MainApplication : Application() {
    companion object {
        lateinit var hawcxSdkInstance: HawcxSDK
            private set
    }

    override fun onCreate() {
        super.onCreate()
        
        // Initialize Hawcx SDK with your project API key
        hawcxSdkInstance = HawcxSDK(
            context = this.applicationContext,
            projectApiKey = "YOUR_API_KEY"
        )
    }
}
Don’t forget to register your Application class in the AndroidManifest.xml:
<application
    android:name=".YourApplication"
    ...>
    <!-- Activities and other components -->
</application>
3

Implement Smart Connect authentication:

Core Features

  • Implementation
  • Compose Example
The revolutionary V4 SDK featuring Hawcx Smart Connect provides intelligent one-click authentication that automatically handles everything:What Smart Connect Does Automatically:
  • Intelligent User Recognition: Automatically detects if user is new or existing
  • Contextual Device Awareness: Knows if device is registered or new
  • Seamless Flow Management: Guides new users through verification, gives existing users instant access
  • Unified Experience: Single entry point - no more “Sign Up” vs “Sign In” confusion
  • Secure OTP Delivery: Sends verification codes only when needed
  • Advanced Cryptography: Manages all security operations transparently
  • Secure Token Storage: Stores credentials safely in Android Keystore
  • Complete Authentication Intelligence: Handles the entire flow behind one smart button
SDK Methods:
  • authenticateV4(userid: String, callback: AuthV4Callback) - Initiates Smart Connect flow
  • submitOtpV4(otp: String) - Submits OTP for verification when needed
  • cancelV4Auth() - Cancels ongoing authentication
SDK Callbacks (AuthV4Callback interface):
  • onOtpRequired() - Called when new user/device verification is needed
  • onAuthSuccess(accessToken: String?, refreshToken: String?, isLoginFlow: Boolean) - Called on successful authentication
  • onError(errorCode: AuthV4ErrorCode, errorMessage: String) - Called when errors occur
  • Implementation
  • Compose Example
Web login enables cross-platform authentication where users can log into your web application using their mobile device with Smart Connect intelligence.Use Case:
  • Your application has both web and mobile versions using Hawcx Smart Connect SDK
  • User visits your web app and initiates login
  • Web app displays a QR code (generated using Hawcx Web SDK with Smart Connect)
  • User scans QR code with mobile app
  • Mobile app shows login session details (browser, location, IP)
  • User approves the login from mobile
  • Web app automatically logs the user in with Smart Connect
What the SDK Does Automatically:
  • Validates PIN with backend
  • Retrieves and stores session details (browser, location, IP)
  • Manages web token for approval
  • Sends approval to complete web login
SDK Methods:
  • webLogin(pin: String, callback: WebLoginCallback) - Validates PIN from QR code
  • webApprove(token: String, callback: WebLoginCallback) - Approves web login session
SDK Callbacks (WebLoginCallback interface):
  • onSuccess() - Called when operation succeeds
  • onError(webLoginErrorCode: WebLoginError, errorMessage: String) - Called on error
SDK Storage:
  • Saves web_token to SharedPreferences after successful PIN validation
  • Saves sessionDetails with browser/location info to SharedPreferences
  • Implementation
  • Compose Example
The SDK works seamlessly with Android biometric authentication and Smart Connect. You implement biometric prompt and verification, then call the SDK’s Smart Connect authentication method:What You Implement:
  • Biometric prompt using BiometricPrompt API
  • Biometric availability checks
  • Biometric preference storage
What the SDK Provides:
  • getLastLoggedInUsername() to retrieve the last authenticated user (suspend function)
  • Smart Connect authenticateV4() for intelligent passwordless login after biometric success
  • Automatic handling of known device login (no OTP required)
Your Implementation:
  1. Check biometric availability using BiometricManager
  2. Show BiometricPrompt
  3. On success, call SDK’s Smart Connect authenticateV4() method
  • Implementation
  • Compose Example
What the SDK Manages:
  • JWT tokens (access & refresh) in Android Keystore
  • Device registration keys in Android Keystore
  • Last logged-in user identifier
  • Secure cleanup of credentials
SDK Methods (all are suspend functions):

suspend fun clearSessionTokens(userid: String): Boolean

Purpose: Standard logout functionality
What it does:
  • Removes JWT access and refresh tokens from Keystore
  • Preserves device registration (Er1r2 and persistent device token)
  • User can log back in without OTP verification
  • Device remains trusted
When to use:
  • Standard “Log Out” button functionality
  • Switching between accounts on same device
  • Temporary sign out
Example:
fun logoutCurrentUser() {
    lifecycleScope.launch {
        val userId = getCurrentUserId()
        val success = sdk.clearSessionTokens(userid = userId)
        if (success) {
            // User will use Smart Connect but no OTP needed
            navigateToSmartConnectScreen()
        }
    }
}

suspend fun clearUserKeychainData(userid: String): Boolean ⚠️

Purpose: Complete device removal
What it does:
  • Removes ALL user data from Keystore:
  • JWT tokens (access & refresh)
  • Device registration keys (Er1r2)
  • Persistent device token
  • All cryptographic material
  • User will need OTP to use this device again
  • Device is no longer trusted
When to use:
  • “Remove this device” functionality
  • Security breach response
  • Before selling/giving away device
  • Complete account removal
⚠️ WARNING: This is destructive! Do NOT use for standard logout.Example:
fun removeDeviceCompletely() {
    lifecycleScope.launch {
        val userId = getCurrentUserId()
        // Confirm with user first!
        showConfirmationDialog("Remove this device?") { confirmed ->
            if (confirmed) {
                lifecycleScope.launch {
                    val success = sdk.clearUserKeychainData(userid = userId)
                    if (success) {
                        // Smart Connect will require OTP next time
                        navigateToSmartConnectScreen()
                    }
                }
            }
        }
    }
}

suspend fun getLastLoggedInUsername(): String

Purpose: UI convenience for Smart Connect screen
What it returns:
  • Email/identifier of last successfully authenticated user
  • Empty string if no user has logged in
When to use:
  • Pre-filling email field on Smart Connect screen
  • Enabling biometric login for returning users
  • Showing “Welcome back, [email]” messages
Example:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    lifecycleScope.launch {
        // Pre-fill email field
        val lastUser = sdk.getLastLoggedInUsername()
        if (lastUser.isNotEmpty()) {
            emailEditText.setText(lastUser)
            
            // Check if biometrics enabled for this user
            if (isBiometricEnabled(lastUser)) {
                showBiometricLoginButton()
            }
        }
    }
}

suspend fun clearLastLoggedInUser(): Boolean

Purpose: Clear the UI pre-fill record
What it does:
  • Only removes the “last user” marker
  • Does NOT affect authentication state
  • Does NOT remove any tokens or keys
  • Next app launch won’t pre-fill email
When to use:
  • “Switch Account” functionality
  • Privacy mode where email shouldn’t be shown
  • App reset (keeping users logged in)
Example:
fun switchToNewAccount() {
    lifecycleScope.launch {
        // Clear pre-fill but keep current user logged in
        sdk.clearLastLoggedInUser()
        
        // Show fresh Smart Connect screen
        presentSmartConnectScreen(preFillEmail = false)
    }
}

Understanding the Difference

ActionMethod to UseUser ExperienceOTP Required?
Log OutclearSessionTokens()Must use Smart Connect again❌ No
Remove DeviceclearUserKeychainData()Device registration lost✅ Yes
Hide Email Pre-fillclearLastLoggedInUser()No change to authN/A
Check Last UsergetLastLoggedInUsername()Shows last emailN/A
  • Implementation
  • Compose Example
The SDK provides detailed error codes through the callback. Here’s how to handle them:SDK Provides:
  • AuthV4ErrorCode enum with specific error cases
  • Human-readable error messages
  • Error details in callback
You Implement:
  • Error UI (alerts, snackbars, toasts)
  • Retry logic
  • Navigation based on error type

Troubleshooting

Symptoms:
  • NETWORK_ERROR returned in callback
  • Smart Connect doesn’t proceed
Solutions:
  1. Check internet connectivity
  2. Verify API key is correct
  3. Ensure no firewall/proxy blocking
  4. Add network permission to manifest:
<uses-permission android:name="android.permission.INTERNET" />
  1. Implement retry logic with exponential backoff:
fun retrySmartConnect(attempts: Int = 3) {
    var currentAttempt = 0
    
    fun attempt() {
        sdk.authenticateV4(userid = email, callback = this)
    }
    
    // In error callback
    if (errorCode == AuthV4ErrorCode.NETWORK_ERROR && currentAttempt < attempts) {
        currentAttempt++
        lifecycleScope.launch {
            delay(currentAttempt * 2000L) // Exponential backoff
            attempt()
        }
    }
}
Symptoms:
  • OTP_VERIFICATION_FAILED error
  • User cannot proceed past OTP screen
Solutions:
  1. Ensure OTP is exactly 6 digits
  2. Check if OTP expired (5 minute validity)
  3. Enable auto-fill for better UX:
// In your OTP EditText
otpEditText.setAutofillHints(View.AUTOFILL_HINT_SMS_OTP)
Symptoms:
  • Biometric prompt doesn’t appear
  • Authentication fails immediately
Solutions:
  1. Add to AndroidManifest.xml:
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
  1. Check biometric availability:
val biometricManager = BiometricManager.from(context)
when (biometricManager.canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)) {
    BiometricManager.BIOMETRIC_SUCCESS ->
        Log.d("Biometric", "App can authenticate using biometrics.")
    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
        Log.e("Biometric", "No biometric features available on this device.")
    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
        Log.e("Biometric", "Biometric features are currently unavailable.")
    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
        Log.e("Biometric", "User hasn't enrolled any biometrics.")
}
  1. Handle specific biometric errors:
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
    when (errorCode) {
        BiometricPrompt.ERROR_USER_CANCELED -> {
            // User cancelled
        }
        BiometricPrompt.ERROR_LOCKOUT -> {
            // Too many attempts
            showMessage("Too many failed attempts. Try again later.")
        }
        BiometricPrompt.ERROR_LOCKOUT_PERMANENT -> {
            // Permanent lockout
            showMessage("Biometric authentication is disabled.")
        }
        else -> {
            showMessage("Biometric error: $errString")
        }
    }
}
Symptoms:
  • KEYCHAIN_SAVE_FAILED errors
  • Login state not persisted
Solutions:
  1. Ensure device has secure lock screen:
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (!keyguardManager.isDeviceSecure) {
    // Prompt user to set up lock screen
}
  1. Handle Keystore exceptions:
try {
    // Keystore operations
} catch (e: UserNotAuthenticatedException) {
    // User needs to unlock device
} catch (e: KeyPermanentlyInvalidatedException) {
    // Keys invalidated, need to re-register
}

Error Codes

  • AuthV4ErrorCode
  • WebLoginError
Error CodeDescription
FINGERPRINT_ERRORFailed to generate device fingerprint
KEYCHAIN_SAVE_FAILEDFailed to save data to Android Keystore
CLIENT_CRYPTO_ERRORCryptographic operation failed on device
AUTH_INIT_FAILEDAuthentication initialization failed
OTP_VERIFICATION_FAILEDInvalid or expired OTP
DEVICE_VERIFICATION_FAILEDDevice registration verification failed
CIPHER_VERIFICATION_FAILEDLogin cipher verification failed
NETWORK_ERRORNetwork connectivity issue or request timeout
INTERNAL_STATE_ERRORSDK internal state corruption
MISSING_DEVICE_TOKEN_SESSIONSession token missing during flow
UNKNOWN_ERRORUnexpected error occurred

Support

I