Skip to main content

sdk.auth.email

sendOTP

Send a one-time password to a user’s email address.
Future<void> sendOTP(String email)

Parameters

  • email (String) - User’s email address

Example

try {
  await sdk.auth.email.sendOTP('[email protected]');
  // Show OTP input UI
} catch (e) {
  print('Failed to send OTP: $e');
}

verifyOTP

Verify an email OTP code and authenticate the user.
Future<void> verifyOTP(String token)

Parameters

  • token (String) - OTP code entered by user

Example

try {
  await sdk.auth.email.verifyOTP('123456');
  // User is now authenticated
} catch (e) {
  print('Invalid OTP: $e');
}

resendOTP

Resend the email OTP.
Future<void> resendOTP()

Example

try {
  await sdk.auth.email.resendOTP();
} catch (e) {
  print('Failed to resend OTP: $e');
}

sdk.auth.sms

sendOTP

Send a one-time password to a user’s phone number via SMS.
Future<void> sendOTP(PhoneData phoneData)

Parameters

  • phoneData (PhoneData) - Phone data containing dial code, ISO code, and phone number

Example

try {
  final phoneData = PhoneData(
    dialCode: '+1',
    iso2: 'US',
    phone: '5551234567',
  );
  await sdk.auth.sms.sendOTP(phoneData);
  // Show OTP input UI
} catch (e) {
  print('Failed to send SMS: $e');
}

verifyOTP

Verify an SMS OTP code and authenticate the user.
Future<void> verifyOTP(String token)

Parameters

  • token (String) - OTP code entered by user

Example

try {
  await sdk.auth.sms.verifyOTP('123456');
  // User is now authenticated
} catch (e) {
  print('Invalid OTP: $e');
}

resendOTP

Resend the SMS OTP.
Future<void> resendOTP()

Example

try {
  await sdk.auth.sms.resendOTP();
} catch (e) {
  print('Failed to resend SMS: $e');
}

sdk.auth.social

connect

Authenticate with a social provider (Google, Apple, Farcaster).
Future<void> connect(SocialProvider provider)

Parameters

  • provider (SocialProvider) - The social provider:
    • SocialProvider.google
    • SocialProvider.apple
    • SocialProvider.farcaster

Examples

try {
  // Google
  await sdk.auth.social.connect(SocialProvider.google);
  // Apple
  await sdk.auth.social.connect(SocialProvider.apple);
  // Farcaster
  await sdk.auth.social.connect(SocialProvider.farcaster);
} catch (e) {
  print('Sign-in failed: $e');
}

sdk.auth.passkey

signIn

Authenticate with a passkey using the device’s biometric authentication.
Future<void> signIn()

Example

try {
  await sdk.auth.passkey.signIn();
  // User is authenticated
} catch (e) {
  print('Passkey sign-in failed: $e');
}

sdk.auth.externalAuth

signInWithExternalJwt

Sign in using an external JWT token.
Future<void> signInWithExternalJwt({required String jwt})

Parameters

  • jwt (String) - The external JWT token

Example

try {
  await sdk.auth.externalAuth.signInWithExternalJwt(
    jwt: 'your-jwt-token',
  );
} catch (e) {
  print('JWT sign-in failed: $e');
}

Authentication State

authenticatedUser

Get the current authenticated user (synchronous).
UserProfile? get authenticatedUser

Example

final user = sdk.auth.authenticatedUser;
if (user != null) {
  print('User: ${user.email}');
}

authenticatedUserChanges

Observe authentication state changes (reactive stream).
Stream<UserProfile?> get authenticatedUserChanges

Example

sdk.auth.authenticatedUserChanges.listen((user) {
  // Handle user state change
  setState(() {
    isAuthenticated = user != null;
  });
});

StreamBuilder Example

StreamBuilder<UserProfile?>(
  stream: sdk.auth.authenticatedUserChanges,
  initialData: sdk.auth.authenticatedUser,
  builder: (context, snapshot) {
    final user = snapshot.data;
    if (user != null) {
      return Text('Logged in as ${user.email}');
    } else {
      return Text('Not logged in');
    }
  },
)

token

Get the current authentication token (synchronous).
String? get token

Example

final token = sdk.auth.token;
if (token != null) {
  print('Token: ${token.substring(0, 20)}...');
}

tokenChanges

Observe authentication token changes (reactive stream).
Stream<String?> get tokenChanges

Example

sdk.auth.tokenChanges.listen((token) {
  if (token != null && token.isNotEmpty) {
    // Token received, navigate to home
    Navigator.pushReplacementNamed(context, '/home');
  }
});

StreamBuilder Example

StreamBuilder<String?>(
  stream: sdk.auth.tokenChanges,
  initialData: sdk.auth.token,
  builder: (context, snapshot) {
    final hasToken = snapshot.data != null && snapshot.data!.isNotEmpty;
    return Text(hasToken ? 'Authenticated' : 'Not authenticated');
  },
)

Logout

logout

Log out the current user.
Future<void> logout()

Example

try {
  await sdk.auth.logout();
} catch (e) {
  print('Logout failed: $e');
}

Complete Authentication Flow Example

Email Authentication

class EmailAuthScreen extends StatefulWidget {
  @override
  _EmailAuthScreenState createState() => _EmailAuthScreenState();
}

class _EmailAuthScreenState extends State<EmailAuthScreen> {
  final sdk = DynamicSDK.instance;
  final emailController = TextEditingController();
  final otpController = TextEditingController();
  bool otpSent = false;
  bool isLoading = false;

  Future<void> handleSendOTP() async {
    setState(() => isLoading = true);

    try {
      await sdk.auth.email.sendOTP(emailController.text);
      setState(() {
        otpSent = true;
        isLoading = false;
      });
    } catch (e) {
      setState(() => isLoading = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to send OTP: $e')),
      );
    }
  }

  Future<void> handleVerifyOTP() async {
    setState(() => isLoading = true);

    try {
      await sdk.auth.email.verifyOTP(otpController.text);
      // User is now authenticated, navigation handled by auth state listener
    } catch (e) {
      setState(() => isLoading = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Invalid OTP: $e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Email Authentication')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            if (!otpSent) ...[
              TextField(
                controller: emailController,
                decoration: InputDecoration(
                  labelText: 'Email',
                  hintText: '[email protected]',
                ),
                keyboardType: TextInputType.emailAddress,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: isLoading ? null : handleSendOTP,
                child: isLoading
                    ? CircularProgressIndicator()
                    : Text('Send OTP'),
              ),
            ] else ...[
              TextField(
                controller: otpController,
                decoration: InputDecoration(
                  labelText: 'Enter OTP',
                  hintText: '123456',
                ),
                keyboardType: TextInputType.number,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: isLoading ? null : handleVerifyOTP,
                child: isLoading
                    ? CircularProgressIndicator()
                    : Text('Verify OTP'),
              ),
              TextButton(
                onPressed: () async {
                  try {
                    await sdk.auth.email.resendOTP();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('OTP resent')),
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Failed to resend: $e')),
                    );
                  }
                },
                child: Text('Resend OTP'),
              ),
            ],
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    emailController.dispose();
    otpController.dispose();
    super.dispose();
  }
}

SMS Authentication

class SmsAuthScreen extends StatefulWidget {
  @override
  _SmsAuthScreenState createState() => _SmsAuthScreenState();
}

class _SmsAuthScreenState extends State<SmsAuthScreen> {
  final sdk = DynamicSDK.instance;
  final phoneController = TextEditingController();
  final otpController = TextEditingController();
  bool otpSent = false;
  bool isLoading = false;

  Future<void> handleSendOTP() async {
    setState(() => isLoading = true);

    try {
      final phoneData = PhoneData(
        dialCode: '+1',
        iso2: 'US',
        phone: phoneController.text,
      );
      await sdk.auth.sms.sendOTP(phoneData);
      setState(() {
        otpSent = true;
        isLoading = false;
      });
    } catch (e) {
      setState(() => isLoading = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to send SMS: $e')),
      );
    }
  }

  Future<void> handleVerifyOTP() async {
    setState(() => isLoading = true);

    try {
      await sdk.auth.sms.verifyOTP(otpController.text);
      // User is now authenticated
    } catch (e) {
      setState(() => isLoading = false);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Invalid OTP: $e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('SMS Authentication')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            if (!otpSent) ...[
              TextField(
                controller: phoneController,
                decoration: InputDecoration(
                  labelText: 'Phone Number',
                  hintText: '5551234567',
                ),
                keyboardType: TextInputType.phone,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: isLoading ? null : handleSendOTP,
                child: isLoading
                    ? CircularProgressIndicator()
                    : Text('Send OTP'),
              ),
            ] else ...[
              TextField(
                controller: otpController,
                decoration: InputDecoration(
                  labelText: 'Enter OTP',
                  hintText: '123456',
                ),
                keyboardType: TextInputType.number,
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: isLoading ? null : handleVerifyOTP,
                child: isLoading
                    ? CircularProgressIndicator()
                    : Text('Verify OTP'),
              ),
              TextButton(
                onPressed: () async {
                  try {
                    await sdk.auth.sms.resendOTP();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('OTP resent')),
                    );
                  } catch (e) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Failed to resend: $e')),
                    );
                  }
                },
                child: Text('Resend OTP'),
              ),
            ],
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    phoneController.dispose();
    otpController.dispose();
    super.dispose();
  }
}

Social Authentication

class SocialAuthButtons extends StatelessWidget {
  final sdk = DynamicSDK.instance;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton.icon(
          onPressed: () async {
            try {
              await sdk.auth.social.connect(SocialProvider.google);
            } catch (e) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Google sign-in failed: $e')),
              );
            }
          },
          icon: Icon(Icons.g_mobiledata),
          label: Text('Continue with Google'),
        ),
        SizedBox(height: 12),
        ElevatedButton.icon(
          onPressed: () async {
            try {
              await sdk.auth.social.connect(SocialProvider.apple);
            } catch (e) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Apple sign-in failed: $e')),
              );
            }
          },
          icon: Icon(Icons.apple),
          label: Text('Continue with Apple'),
        ),
        SizedBox(height: 12),
        ElevatedButton.icon(
          onPressed: () async {
            try {
              await sdk.auth.social.connect(SocialProvider.farcaster);
            } catch (e) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Farcaster sign-in failed: $e')),
              );
            }
          },
          icon: Icon(Icons.telegram),
          label: Text('Continue with Farcaster'),
        ),
      ],
    );
  }
}

Passkey Authentication

class PasskeyAuthButton extends StatelessWidget {
  final sdk = DynamicSDK.instance;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton.icon(
      onPressed: () async {
        try {
          await sdk.auth.passkey.signIn();
          // User is authenticated
        } catch (e) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Passkey sign-in failed: $e')),
          );
        }
      },
      icon: Icon(Icons.fingerprint),
      label: Text('Sign in with Passkey'),
    );
  }
}