RAuth Flutter SDK v2

Cross-platform Flutter library for RAuth v2 reverse authentication. Supports WhatsApp, Reverse SMS, OneID, and Passkey authentication methods.

Features

  • Multiple Auth Methods: WhatsApp, Reverse SMS, OneID, Passkey
  • Cross-Platform: Android, iOS, and Web support
  • Auto Device Detection: Automatic device info and IP detection
  • HMAC Signing: Secure mobile authentication
  • Start Verification: Automatically opens verification intents/deeplinks
  • Await Verification: Automatic session verification
  • Session State Management: Session token and phone stored internally - no need to pass repeatedly
  • Passkey Support: WebAuthn passkey registration with biometric authentication
  • Simplified Passkey API: One-line passkey registration and approval with automatic challenge-response handling
  • Approval System: Request approval tokens for sensitive actions with passkey signature verification

Installation

Add to your pubspec.yaml:

dependencies:
  rauth_flutter: ^2.0.0

Then run:

flutter pub get

Quick Start

1. Initialize RAuth

import 'package:rauth_flutter/rauth_flutter.dart';

void main() {
  Rauth.init(RauthConfig(
    appId: 'your-app-id',
    appSecret: 'your-app-secret',
    debug: false, // Optional, enable debug logs
  ));
  
  runApp(MyApp());
}

2. Start Authentication Session

// Start session with WhatsApp
final session = await Rauth.instance.startSession(
  phone: '+1234567890',
  loginMethod: LoginMethod.whatsapp,
);

// Get QR code for display
final qrCode = session.getQR(); // Automatically gets QR from any method

// Display QR code in your UI

3. Start Verification

// Automatically opens the appropriate verification method
// - WhatsApp: Shows native chooser if both apps available, otherwise opens directly
// - SMS: 
//   - If permissions granted: Sends SMS automatically in background (with SIM selection on dual SIM)
//   - If permissions not granted: Opens SMS app for manual sending
// - OneID: Opens deeplink directly

await session.startVerification();

4. Await Verification

try {
  // ✅ No need to pass sessionToken & phone - stored internally!
  final status = await session.awaitVerification();

  // Session verified!
  print('Verified via: ${status.verifiedVia}');
  
  // Send session token to your backend
  final jwt = await yourBackend.authenticate(
    sessionToken: status.token,
    phone: status.phone,
  );
} on TimeoutError {
  print('Verification timeout');
} on SessionRevokedError {
  print('Session was revoked');
}

Note: The session token and phone number are automatically stored when you call startSession(). You don't need to pass them again!

Complete Example

Login Flow

import 'package:rauth_flutter/rauth_flutter.dart';

class AuthService {
  Future<void> loginWithWhatsApp(String phone) async {
    try {
      // 1. Initialize session
      final session = await Rauth.instance.startSession(
        phone: phone,
        loginMethod: LoginMethod.whatsapp,
      );

      // 2. Show QR code
      final qrCode = session.getQR(); // Automatically gets QR from any method
      // Display QR code in UI

      // 3. Start verification (opens WhatsApp/SMS/OneID)
      await session.startVerification();

      // 4. Await verification (sessionToken & phone stored internally)
      final status = await session.awaitVerification();

      // 4. Send to backend
      // NOTE: If you are doing signup, you can include additional fields
      // like username, dob, gender along with phone and session_token.
      final jwt = await http.post(
        Uri.parse('https://your-api.com/auth/login'),
        body: jsonEncode({
          'session_token': status.token,
          'phone': status.phone,
          // Optional (for signup):
          // 'username': 'john_doe',
          // 'dob': '1995-08-20',
          // 'gender': 'male',
        }),
      );

      // 5. Store JWT and proceed
      await saveJWT(jwt);
    } catch (e) {
      if (e is TimeoutError) {
        print('Verification timeout');
      } else if (e is SessionRevokedError) {
        print('Session revoked');
      } else {
        print('Error: $e');
      }
    }
  }
}

Passkey Support

RAuth Flutter SDK supports native WebAuthn/Passkeys across all platforms for secure approval flows. Passkeys provide phishing-resistant authentication using device biometrics (fingerprint, face recognition) or PIN.

Platform Support

Platform Minimum Version Native API Sync Support
Web All modern browsers WebAuthn API Browser-based
iOS iOS 16.0+ Passkeys API (ASAuthorizationController) iCloud Keychain sync
Android 14+ Android 14+ CredentialManager API Google Password Manager sync
Android 9-13 Android 9+ Fido2ApiClient (Google Play Services) Google Password Manager sync

Note: On older Android versions (below 9) or if native APIs are unavailable, the library automatically falls back to a secure custom implementation.

Quick Start: Passkey Registration & Approval

Simplified API - Everything handled automatically!

// After session is verified
final session = await Rauth.instance.startSession(
  phone: '+1234567890',
  loginMethod: LoginMethod.whatsapp,
);
await session.startVerification();
final status = await session.awaitVerification();

// 1. Register passkey (one line!)
// ✅ Automatically prompts for biometric/PIN
// ✅ Works on Web, iOS 16+, Android 9+
await session.registerPasskeyWithBiometric();

// 2. Request approval token with passkey (one line!)
// ✅ Automatically handles challenge-response flow
// ✅ Prompts for biometric authentication
final approval = await session.requestApprovalTokenWithPasskey(
  action: ApprovalAction.transfer,
  amount: 1000.50,
  description: 'Transfer to John Doe',
  metadata: {
    'recipient': 'john.doe@example.com',
    'account_number': '1234567890',
  },
);

// 3. Use approval token in your backend request
final transferResponse = await http.post(
  Uri.parse('https://your-api.com/transfer'),
  headers: {
    'Authorization': 'Bearer $jwt',
    'X-Approval-Token': approval.approvalToken,
  },
  body: jsonEncode({
    'amount': 1000.50,
    'recipient': 'john.doe@example.com',
  }),
);

What Happens Automatically

The library handles everything for you:

  • Biometric prompts: Native platform UI (Face ID, Touch ID, fingerprint, PIN)
  • Challenge-response flow: Two-step approval with automatic retry
  • Platform-specific APIs: Uses native WebAuthn on each platform
  • Session management: No need to pass sessionToken/phone repeatedly
  • Error handling: Automatic fallback if native APIs unavailable

Platform-Specific Behavior

Web

  • Uses browser's WebAuthn API
  • Shows native browser passkey dialog
  • Works on Chrome, Safari, Firefox, Edge
  • Passkeys sync via browser's password manager

iOS 16+

  • Uses native Passkeys API
  • Shows iOS system passkey dialog
  • Requires Face ID, Touch ID, or device passcode
  • Passkeys sync via iCloud Keychain across Apple devices

Android 14+

  • Uses CredentialManager API
  • Shows Google Password Manager passkey dialog
  • Requires fingerprint, face unlock, or device PIN
  • Passkeys sync via Google Password Manager

Android 9-13

  • Uses Fido2ApiClient (via Google Play Services)
  • Shows Google Password Manager passkey dialog
  • Requires fingerprint, face unlock, or device PIN
  • Passkeys sync via Google Password Manager
  • Note: Requires Google Play Services to be installed

Complete Example: Bank Transfer with Passkey

class TransferService {
  Future<void> transferMoney({
    required double amount,
    required String recipient,
  }) async {
    try {
      // Request approval with passkey
      final approval = await Rauth.instance.requestApprovalTokenWithPasskey(
        action: ApprovalAction.transfer,
        amount: amount,
        description: 'Transfer to $recipient',
        metadata: {'recipient': recipient},
        requireBiometric: true,
        localizedReason: 'Authenticate to complete transfer',
      );

      // Execute transfer with approval token
      await http.post(
        Uri.parse('https://your-api.com/transfer'),
        headers: {
          'Authorization': 'Bearer $jwt',
          'X-Approval-Token': approval.approvalToken,
        },
        body: jsonEncode({
          'amount': amount,
          'recipient': recipient,
        }),
      );

      print('Transfer successful!');
    } catch (e) {
      if (e.toString().contains('Passkey not registered')) {
        // Auto-register passkey if not registered
        await Rauth.instance.registerPasskeyWithBiometric(
          localizedReason: 'Register passkey for secure transfers',
        );
        // Retry transfer
        await transferMoney(amount: amount, recipient: recipient);
      } else {
        print('Transfer failed: $e');
      }
    }
  }
}

API Reference

Rauth.init()

Initialize RAuth with configuration.

Rauth.init(RauthConfig(
  appId: 'your-app-id',
  appSecret: 'your-app-secret',
  debug: false, // Optional, enable debug logs
));

Parameters:

  • appId: Your RAuth app ID from dashboard
  • appSecret: Your RAuth app secret for HMAC signing
  • debug: Enable debug logging (default: false)

Rauth.instance.startSession()

Start a new authentication session.

Future<SessionInitResponse> startSession({
  required String phone,
  required LoginMethod loginMethod,
  String? ipOverride,
  String? locationOverride,
  String? deviceNameOverride,
  String? browserOverride,
  String? platformOverride,
  String? deviceFingerprintOverride,
})

Parameters:

  • phone: Phone number in international format (e.g., "+1234567890")
  • loginMethod: LoginMethod.whatsapp, LoginMethod.reverseSms, LoginMethod.oneid, or LoginMethod.passkey
  • Device info overrides: Optional parameters to override auto-detected device info

Returns: SessionInitResponse with sessionToken and verificationLinks

Note: The session token and phone number are automatically stored internally for use in subsequent calls.

session.startVerification()

Start verification by opening the appropriate intent/deeplink. This method automatically detects the login method and handles the verification flow.

Future<void> startVerification()

No parameters needed! Works automatically based on session data.

Behavior:

  • WhatsApp: Shows native Android chooser if both regular/business deeplinks available, otherwise opens directly
  • SMS:
    • If app has SEND_SMS and READ_PHONE_STATE permissions: SMS is sent automatically in background with SIM selection dialog (on dual SIM devices)
    • If permissions not granted: Opens default SMS app with pre-filled phone number and message (user sends manually)
  • OneID: Directly opens deeplink

Note: No phone parameter needed - only uses deeplinks/tokens from session. No extra setup required - works out of the box!

Session State Management

The library automatically stores session state when you call startSession()!

  • sessionToken and phone are stored internally
  • ✅ No need to pass them repeatedly in subsequent calls
  • ✅ All methods can use stored state automatically
  • ✅ Optional parameters allow override if needed

Await session verification using stored session state.

Future<SessionStatusResponse> awaitVerification({
  int interval = 1,
  int timeout = 900,
})

No parameters needed! Uses session state stored by startSession().

Returns: SessionStatusResponse when verified

Throws:

  • TimeoutError: If timeout reached
  • SessionRevokedError: If session is revoked
  • SessionNotVerifiedError: If session expired

Rauth.instance.awaitVerification() (Alternative)

Await session verification with optional parameters.

Future<SessionStatusResponse> awaitVerification({
  String? sessionToken,  // Optional - uses stored if not provided
  String? phone,         // Optional - uses stored if not provided
  int interval = 1,
  int timeout = 900,
})

Parameters:

  • sessionToken: Optional - uses stored session token if not provided
  • phone: Optional - uses stored phone if not provided
  • interval: Polling interval in seconds (default: 1)
  • timeout: Maximum time to wait in seconds (default: 900)

Rauth.instance.checkSessionStatus()

Check session status once.

Future<SessionStatusResponse> checkSessionStatus({
  String? sessionToken,  // Optional - uses stored if not provided
  String? phone,         // Optional - uses stored if not provided
})

Register a passkey with biometric authentication - handles everything automatically!

Future<PasskeyRegistrationResponse> registerPasskeyWithBiometric({
  String? localizedReason,
})

What it does:

  • ✅ Prompts for biometric authentication (Face ID, Touch ID, fingerprint, PIN)
  • ✅ Uses native WebAuthn APIs on each platform
  • ✅ Registers passkey with backend automatically
  • ✅ Uses stored session state automatically

Parameters:

  • localizedReason: Optional reason shown in biometric prompt (e.g., "Register passkey for secure transfers")

No sessionToken/phone needed! Uses session state stored by startSession().

Platform behavior:

  • Web: Shows browser's native passkey registration dialog
  • iOS 16+: Shows iOS system passkey dialog with Face ID/Touch ID
  • Android 14+: Shows Google Password Manager passkey dialog
  • Android 9-13: Shows Google Password Manager passkey dialog (requires Google Play Services)

Rauth.instance.registerPasskeyWithBiometric() (Alternative)

Register a passkey with optional session override.

Future<PasskeyRegistrationResponse> registerPasskeyWithBiometric({
  String? sessionToken,      // Optional - uses stored if not provided
  String? phone,             // Optional - uses stored if not provided
  String? localizedReason,
})

Note: Passkey registration is mandatory before requesting approval tokens. The library automatically registers passkey if not already registered when calling requestApprovalTokenWithPasskey().

Request approval token with passkey - handles challenge-response automatically!

Future<ApprovalResponse> requestApprovalTokenWithPasskey({
  required ApprovalAction action,
  double? amount,
  String? description,
  Map<String, dynamic>? metadata,
  bool requireBiometric = true,
  String? localizedReason,
})

What it does:

  • ✅ Auto-registers passkey if not already registered
  • ✅ Prompts for biometric authentication (Face ID, Touch ID, fingerprint, PIN)
  • ✅ Requests approval from backend (may receive challenge)
  • ✅ Signs challenge automatically using native WebAuthn
  • ✅ Retries with signature automatically
  • ✅ Uses stored session state automatically

Parameters:

  • action: Approval action type (transfer, withdraw, deleteAccount, etc.)
  • amount: Optional amount for financial actions
  • description: Optional description
  • metadata: Optional metadata map
  • requireBiometric: Whether to require biometric (default: true)
  • localizedReason: Optional reason shown in biometric prompt

Returns: ApprovalResponse with approvalToken that expires in 15 minutes

No sessionToken/phone needed! Uses session state stored by startSession().

Platform behavior:

  • Web: Uses browser's WebAuthn API for challenge signing
  • iOS 16+: Uses iOS Passkeys API with Face ID/Touch ID
  • Android 14+: Uses CredentialManager API with fingerprint/face unlock
  • Android 9-13: Uses Fido2ApiClient with fingerprint/face unlock

Rauth.instance.requestApprovalTokenWithPasskey() (Alternative)

Request approval token with optional session override.

Future<ApprovalResponse> requestApprovalTokenWithPasskey({
  String? sessionToken,      // Optional - uses stored if not provided
  String? phone,             // Optional - uses stored if not provided
  required ApprovalAction action,
  double? amount,
  String? description,
  Map<String, dynamic>? metadata,
  bool requireBiometric = true,
  String? localizedReason,
})

Approval Actions:

  • ApprovalAction.transfer - Money transfer
  • ApprovalAction.withdraw - Withdrawal request
  • ApprovalAction.deleteAccount - Account deletion
  • ApprovalAction.changePassword - Password change
  • ApprovalAction.sessionVerification - Session verification

Permissions (Android)

The following permissions are required for automatic SMS verification and are included in the library's AndroidManifest.xml:

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Permission Behavior for SMS Verification

If both SEND_SMS and READ_PHONE_STATE permissions are granted:

  • ✅ SMS is sent automatically in the background
  • ✅ On dual SIM devices: Shows native SIM selection dialog, then sends SMS from selected SIM
  • ✅ On single SIM devices: Sends SMS directly
  • ✅ Seamless user experience (like UPI apps)

If permissions are not granted:

  • 📱 Opens default SMS app with pre-filled phone number and message via ACTION_SENDTO intent
  • 👤 User manually sends the SMS
  • ✅ Works without any permissions (fallback to manual SMS)

Note: The library automatically detects permissions and adapts behavior. No additional configuration needed!

Device Info Auto-Detection

The SDK automatically detects device information:

  • Mobile (Android/iOS):

    • device_name: Device model (e.g., "iPhone 15", "Pixel 7")
    • platform: OS version (e.g., "iOS 17", "Android 14")
    • browser: Empty (not applicable)
    • ip: Auto-fetched public IP
  • Web:

    • device_name: null
    • platform: OS name (e.g., "Windows 11", "macOS", "Linux")
    • browser: Browser name + version (e.g., "Chrome 120")
    • ip: Auto-fetched public IP

All fields can be overridden using optional parameters in startSession().

Error Handling

try {
  await Rauth.instance.startSession(...);
} on NetworkError catch (e) {
  // Network/connection issues
} on AuthError catch (e) {
  // Authentication failed (401, 403)
} on ValidationError catch (e) {
  // Invalid input (400, 402)
} on TimeoutError catch (e) {
  // Verification timeout
} on SessionRevokedError catch (e) {
  // Session was revoked
} on RauthException catch (e) {
  // Other RAuth errors
}

Platform Support

Authentication Methods

  • ✅ Android (9+)
  • ✅ iOS (12+)
  • ✅ Web (Chrome, Safari, Firefox, Edge)

Passkey Support

  • Web: All modern browsers (WebAuthn API)
  • iOS: iOS 16.0+ (Native Passkeys API)
  • Android 14+: CredentialManager API
  • Android 9-13: Fido2ApiClient (requires Google Play Services)
  • Fallback: Custom secure implementation for older devices

License

MIT

Support

For issues and questions, visit https://rauth.io or contact support@rauth.io

Libraries

rauth_flutter