vestibule_auth 0.0.1-beta.1 copy "vestibule_auth: ^0.0.1-beta.1" to clipboard
vestibule_auth: ^0.0.1-beta.1 copied to clipboard

Multi-tenant OTP authentication client for Vestibule

Vestibule Auth #

A Flutter authentication client for Vestibule, providing secure multi-tenant OTP and social sign-in capabilities.

Features #

  • Email OTP Authentication - Send and verify one-time passwords via email
  • SMS OTP Authentication - Send and verify one-time passwords via SMS
  • Multi-Factor Authentication - Chain multiple authentication factors (e.g., email + phone)
  • Social Sign-In - Authenticate with Google and Apple
  • Device Fingerprinting - Automatic device identification for security
  • Secure Token Management - JWT and refresh token handling with automatic storage
  • Multi-Tenant Support - Isolated authentication per tenant ID

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  vestibule_auth: ^0.0.1

Then run:

flutter pub get

Usage #

Initialize the Client #

import 'package:vestibule_auth/client.dart';

final authClient = VestibuleClient(
  serverUrl: 'https://your-vestibule-server.com',
  tenantId: 'your-tenant-id',
);

Email OTP Authentication #

// Request OTP
final requestResult = await authClient.requestOTP(
  recipient: 'user@example.com',
  deliveryMethod: DeliveryMethod.DELIVERY_METHOD_EMAIL,
);

// Verify OTP
final verifyResult = await authClient.verifyOTP(
  recipient: 'user@example.com',
  code: '123456',
);

if (verifyResult.hasJwt()) {
  final jwt = verifyResult.jwt;
  final refreshToken = verifyResult.refreshToken;
  // User is authenticated
}

SMS OTP Authentication #

// Request OTP
final requestResult = await authClient.requestOTP(
  recipient: '+1234567890',
  deliveryMethod: DeliveryMethod.DELIVERY_METHOD_SMS,
);

// Verify OTP
final verifyResult = await authClient.verifyOTP(
  recipient: '+1234567890',
  code: '123456',
);

Multi-Factor Authentication #

Vestibule supports chaining multiple authentication factors:

// Step 1: Verify email (first factor)
final emailResult = await authClient.verifyOTP(
  recipient: 'user@example.com',
  code: '123456',
);

String? verifyToken;
if (emailResult.hasVerifyToken()) {
  verifyToken = emailResult.verifyToken;
  // First factor verified, need second factor
}

// Step 2: Request phone OTP (second factor)
await authClient.requestOTP(
  recipient: '+1234567890',
  deliveryMethod: DeliveryMethod.DELIVERY_METHOD_SMS,
);

// Step 3: Verify phone with verify token
final phoneResult = await authClient.verifyOTP(
  recipient: '+1234567890',
  code: '654321',
  verifyToken: verifyToken,
);

if (phoneResult.hasJwt()) {
  // User is fully authenticated
}

Social Sign-In #

Google Sign-In

final result = await authClient.signInWithGoogle();

if (result.hasJwt()) {
  // User is authenticated
} else if (result.hasVerifyToken()) {
  // Additional factor required (e.g., phone verification)
}

Apple Sign-In

final result = await authClient.signInWithApple();

if (result.hasJwt()) {
  // User is authenticated
} else if (result.hasVerifyToken()) {
  // Additional factor required (e.g., phone verification)
}

Token Management #

The client provides secure token storage using flutter_secure_storage:

// Save tokens after authentication
final verifyResult = await authClient.verifyOTP(
  recipient: 'user@example.com',
  code: '123456',
);

if (verifyResult.hasJwt() && verifyResult.hasRefreshToken()) {
  await authClient.saveTokens(
    jwt: verifyResult.jwt,
    refreshToken: verifyResult.refreshToken,
  );
}

// Get stored JWT
final jwt = await authClient.getStoredJWT();

// Get stored refresh token
final refreshToken = await authClient.getStoredRefreshToken();

// Refresh stored token automatically
final success = await authClient.refreshStoredToken();
if (success) {
  // Token refreshed and saved automatically
  final newJwt = await authClient.getStoredJWT();
}

// Clear stored tokens (logout)
await authClient.clearTokens();

Automatic Token Storage

Enable automatic token storage to save tokens after successful authentication:

final authClient = VestibuleClient(
  serverUrl: 'https://your-vestibule-server.com',
  tenantId: 'your-tenant-id',
  autoSaveTokens: true, // Automatically save tokens after authentication
);

// Tokens are automatically saved after successful authentication
final result = await authClient.verifyOTP(
  recipient: 'user@example.com',
  code: '123456',
);
// No need to manually call saveTokens()

Manual Token Storage

For more control over token persistence, disable automatic storage:

final authClient = VestibuleClient(
  serverUrl: 'https://your-vestibule-server.com',
  tenantId: 'your-tenant-id',
  // autoSaveTokens defaults to false
);

// Manually save tokens when needed
final result = await authClient.verifyOTP(
  recipient: 'user@example.com',
  code: '123456',
);

if (result.hasJwt() && result.hasRefreshToken()) {
  await authClient.saveTokens(
    jwt: result.jwt,
    refreshToken: result.refreshToken,
  );
}

Device Information #

The client automatically collects device information for security purposes:

final deviceInfo = await authClient.getDeviceInfo();
// Returns: DeviceInfo with device ID, OS, model, etc.

Configuration #

Android Setup #

For Google Sign-In on Android, add your OAuth client ID to android/app/src/main/res/values/strings.xml:

<string name="default_web_client_id">YOUR_WEB_CLIENT_ID</string>

iOS Setup #

For Apple Sign-In on iOS, enable the "Sign in with Apple" capability in Xcode.

For Google Sign-In on iOS, add your reversed client ID to Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>YOUR_REVERSED_CLIENT_ID</string>
    </array>
  </dict>
</array>

API Reference #

VestibuleClient #

Constructor

VestibuleClient({
  required String serverUrl,
  required String tenantId,
  Transport? transport,
  GoogleSignIn? googleSignIn,
  FlutterSecureStorage? secureStorage,
  bool autoSaveTokens = false,
})

Parameters:

  • serverUrl - Your Vestibule server URL
  • tenantId - Your tenant ID
  • transport - Optional custom transport (for testing)
  • googleSignIn - Optional GoogleSignIn instance (required for Google auth)
  • secureStorage - Optional custom secure storage (for testing)
  • autoSaveTokens - When true, automatically saves tokens after successful authentication. Default: false

Methods

Authentication

  • requestOTP({required String recipient, required DeliveryMethod deliveryMethod}) - Request an OTP code
  • verifyOTP({required String recipient, required String code, String? verifyToken}) - Verify an OTP code
  • signInWithGoogle() - Authenticate with Google
  • signInWithApple() - Authenticate with Apple

Token Management

  • saveTokens({required String jwt, required String refreshToken}) - Store tokens in secure storage
  • getStoredJWT() - Get stored JWT token
  • getStoredRefreshToken() - Get stored refresh token
  • refreshToken({required String refreshToken}) - Refresh a JWT using a refresh token
  • refreshStoredToken() - Refresh and save the stored JWT automatically
  • clearTokens() - Clear stored tokens from secure storage

Utilities

  • getPublicKey() - Get tenant's public key for JWT verification
  • getDeviceInfo() - Get device information

Response Types #

All authentication methods return a response with:

  • jwt - JWT access token (if authentication is complete)
  • refreshToken - Refresh token (if authentication is complete)
  • verifyToken - Verification token (if additional factors are required)
  • message - Response message

Example #

See the example directory for a complete Flutter app demonstrating all authentication methods.

License #

See LICENSE file for details.