Privy Flutter SDK
The Privy Flutter SDK is a Flutter plugin that connects your application to native Privy SDKs for iOS and Android. It enables authentication, non-custodial embedded wallets, and user management by leveraging Privy's platform-specific capabilities.
Features
Authentication
- Login with Phone
- Login with Email
- Login with Custom Auth
- Login with OAuth (Google, Apple, Twitter, Discord)
- Login with SIWE (Sign-In with Ethereum)
Embedded Wallets (Ethereum & Solana)
- Wallet Creation
- Automatic Recovery
- Signing Messages & Transactions
Ethereum-Only Features
- Broadcasting Transactions
- Multiple Embedded Wallets
Getting Started
Requirements
- Flutter: 3.24.0+
- Dart: 3.0.0+
- Android: API 27+ (8.1 Oreo or newer)
- iOS: 16+
Installation
Add the latest Privy SDK dependency to your pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
privy_flutter: ^0.0.1 # Replace with the latest version
Run:
flutter pub get
Configuration
Registering Your App
You must configure your App ID and Client ID in the Privy Developer Dashboard.
- iOS: Add your app's Bundle Identifier under Settings → Clients.
- Android: Add your Application ID from
build.gradle
. - Register Allowed URL Schemes for OAuth authentication in
Info.plist
(iOS) andAndroidManifest.xml
(Android).
Initialization
Import and configure Privy in your Flutter app:
import 'package:privy_flutter/privy_flutter.dart';
final privyConfig = PrivyConfig(
appId: "YOUR_APP_ID",
appClientId: "YOUR_CLIENT_ID",
);
final privy = Privy(config: privyConfig);
Get the Current Authentication State
When the Privy SDK is initialized, the user's authentication state will be set to NotReady until Privy finishes initialization. During this time, we suggest you show a loading state to your user. For you convenience, we've added a suspending getAuthState() function. Here's an example with some pseudocode:
await privy.getAuthState();
Authentication
Login with Email
Authenticate users via email-based OTP verification.
Step 1: Send OTP to User’s Email
final result = await privy.email.sendCode("user@example.com");
- Success(): OTP was sent successfully.
- Failure(PrivyException): Error sending OTP.
Step 2: Verify OTP and Login
final loginResult = await privy.email.loginWithCode(code: "123456", email: "user@example.com");
- Success(PrivyUser): User authenticated successfully.
- Failure(PrivyException): Invalid OTP or authentication failed.
Link Email to Existing Account
final linkResult = await privy.email.linkWithCode(code: "123456", email: "user@example.com");
- Success(): Email linked successfully to current user.
- Failure(PrivyException): Invalid OTP, user not authenticated, or linking failed.
Update User's Email
final updateResult = await privy.email.updateWithCode(code: "123456", email: "newemail@example.com");
- Success(): Email updated successfully.
- Failure(PrivyException): Invalid OTP, user not authenticated, or update failed.
Login with Phone
Authenticate users via SMS-based OTP verification.
Step 1: Send OTP to User’s Phone Number
final result = await privy.sms.sendCode("+14155552671");
- Success(): OTP was sent successfully.
- Failure(PrivyException): Error sending OTP.
Step 2: Verify OTP and Login
final loginResult = await privy.sms.loginWithCode(code: "123456", phoneNumber: "+14155552671");
- Success(PrivyUser): User authenticated successfully.
- Failure(PrivyException): Invalid OTP or authentication failed.
Link Phone Number to Existing Account
final linkResult = await privy.sms.linkWithCode(code: "123456", phoneNumber: "+14155552671");
- Success(): Phone number linked successfully to current user.
- Failure(PrivyException): Invalid OTP, user not authenticated, or linking failed.
Update User's Phone Number
final updateResult = await privy.sms.updateWithCode(code: "123456", phoneNumber: "+14155559999");
- Success(): Phone number updated successfully.
- Failure(PrivyException): Invalid OTP, user not authenticated, or update failed.
Login with Custom Auth
Authenticate users using a third-party authentication provider.
final loginResult = await privy.customAuth.loginWithCustomAccessToken();
- Success(PrivyUser): User authenticated successfully.
- Failure(PrivyException): Invalid or expired token.
Login with OAuth
The Flutter SDK supports OAuth login with Google, Apple, Twitter, and Discord. For all other OAuth providers, use JWT-based authentication.
Platform Configuration
Android: Add to android/app/src/main/AndroidManifest.xml
:
<activity
android:name="io.privy.sdk.oAuth.PrivyRedirectActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="YOUR_CUSTOM_PRIVY_OAUTH_SCHEME" />
</intent-filter>
</activity>
iOS: Add to ios/Runner/Info.plist
:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>privy.oauth</string>
<key>CFBundleURLSchemes</key>
<array>
<string>YOUR_CUSTOM_PRIVY_OAUTH_SCHEME</string>
</array>
</dict>
</array>
Note: Apple Sign In requires iOS 13.0+ and additional configuration in Xcode (Sign in with Apple capability). It is only available on iOS, not on Android Devices.
Usage
final result = await privy.oAuth.login(
provider: OAuthProvider.google, // .google, .apple, .twitter, .discord
appUrlScheme: 'your-app-scheme',
);
result.fold(
onSuccess: (user) => print('Login successful: ${user.id}'),
onFailure: (error) => print('Login failed: $error'),
);
Login with SIWE (Sign-In with Ethereum)
Authenticate users by having them sign a SIWE message with their Ethereum wallet.
Step 1: Generate SIWE Message
final params = SiweMessageParams(
appDomain: "your-app.com",
appUri: "https://your-app.com",
chainId: "1", // Ethereum mainnet
walletAddress: "0x...", // User's wallet address
);
final messageResult = await privy.siwe.generateSiweMessage(params);
Step 2: Have User Sign Message & Login
// User signs the message with their wallet (outside of Privy)
final signature = "0x..."; // Signature from user's wallet
final loginResult = await privy.siwe.loginWithSiwe(
message: message,
signature: signature,
params: params,
metadata: WalletLoginMetadata(
walletClientType: WalletClientType.metamask,
connectorType: "wallet_connect",
),
);
- Success(PrivyUser): User authenticated successfully.
- Failure(PrivyException): Invalid signature or authentication failed.
Get Access Token
Retrieve the user's authentication token for API requests.
final user = await privy.getUser();
final getAccessTokenResult = await user?.getAccessToken();
- Success(String): Token retrieved successfully.
- Failure(PrivyException): User not authenticated or error occurred.
Refresh User Data
Manually refresh the user data to ensure you have the latest information.
final user = await privy.getUser();
final refreshResult = await user?.refresh();
- Success(void): User data refreshed successfully.
- Failure(PrivyException): Error occurred while refreshing user data.
Embedded Wallets
Create an Ethereum Wallet
Creates a non-custodial Ethereum embedded wallet for the user.
final user = await privy.getUser();
final walletResult = await user?.createEthereumWallet();
- Success(EmbeddedEthereumWallet): Wallet created successfully.
- Failure(PrivyException): User not authenticated, network error, or wallet limit exceeded.
Create a Solana Wallet
Creates a non-custodial Solana embedded wallet for the user. You can create multiple wallets by setting createAdditional
to true.
final user = await privy.getUser();
// Create initial wallet
final walletResult = await user?.createSolanaWallet();
// Create additional wallet
final additionalWalletResult = await user?.createSolanaWallet(createAdditional: true);
- Success(EmbeddedSolanaWallet): Wallet created successfully.
- Failure(PrivyException): User not authenticated or network error.
Sign a Message (Solana)
Sign a message using the user’s Solana embedded wallet.
final user = await privy.getUser();
final signature = await user?.embeddedSolanaWallets.first.provider.signMessage("message");
- Success(String): Signature generated successfully.
- Failure(PrivyException): User not authenticated or wallet not found.
Logout
Logs the user out and clears the persisted session.
await privy.logout();
- Success(): User logged out successfully.
- Failure(PrivyException): Error during logout.
Error Handling
All SDK responses use Result<T>
. Handle success or failure using either .fold()
or a switch
statement.
Using .fold()
The .fold()
method allows you to execute separate callbacks for success and failure.
result.fold(
onSuccess: (user) => print("Success: ${user.id}"),
onFailure: (error) => print("Error: ${error.message}"),
);
Using a switch
Statement
Alternatively, you can use a switch
statement to handle success and failure.
switch (result) {
case Success(:final user): // Extracts `user` from Success<T>
print("Success: ${user.id}");
break;
case Failure(:final error): // Extracts `error` from Failure<T>
print("Error: ${error.message}");
break;
}
License
This project is licensed under the MIT License.
For more details, visit the Privy Developer Dashboard.