Flutter (Dart) - Auth

Interacting with Particle Auth within applications made using Flutter

Particle Auth for Flutter

The Particle Auth Flutter SDK enables full stack integration of Particle Auth into applications built on Flutter. This includes everything from the initial configuration of Particle's Wallet-as-a-Service to specific interactions. Specifically in this case, Flutter can be leveraged in either Android or iOS environments, both to the same degree. This is done primarily through Dart.

Platform-specific configuration instructions, alongside examples of utilization, can be found below.

Getting Started

Interaction with the Particle Auth Flutter SDK is quite standard and in line with other Particle Auth SDKs, although the key deviations can be found within the configuration process. The configuration process of this SDK differs significantly based on whether you're using Flutter on Android or iOS.

To begin, you'll need to head over to the Particle dashboard and retrieve your projectId, clientKey, and appId.

  1. Sign up/log in to the Particle dashboard.

  1. Create a new project or enter an existing project.

  1. Create a new application, or skip this step if you already have one.

  1. Retrieve the project ID (projectId), the client key (clientKey), and the application ID (appId).

‎‎

‎‎

‎‎

Adding the Particle Auth Flutter SDK to your application

Additionally, regardless of platform, you'll need to begin by adding particle_auth_core to your Flutter application; this is a requirement before moving onto platform-specific configuration.

flutter pub add particle_auth_core 

// Alternatively, to use Auth (deprecated)
// flutter pub add particle_auth

Android configuration

If you're building an Android application with Flutter, you must follow the steps below to configure Particle Auth. To begin, you'll need to go ahead and open your build.gradle file, often found at the following file path: ${project name}/android/app/build.gradle

Within your build.gradle file, you'll need to add four new lines to ensure Particle Auth runs appropriately:

  1. minSdkVersion, which in most cases will be set to 23.
  2. manifestPlaceholders["PN_PROJECT_ID"], the projectId previously retrieved from the Particle dashboard.
  3. manifestPlaceholders["PN_PROJECT_CLIENT_KEY"], the clientKey previously retrieved from the Particle dashboard.
  4. manifestPlaceholders["PN_APP_ID"], the appId previously retrieved from the Particle dashboard.
// Example
defaultConfig {
  applicationId "com.example.particle_auth_test"

  minSdkVersion 23 // Required by Particle Auth
  targetSdkVersion flutter.targetSdkVersion
  versionCode flutterVersionCode.toInteger()
  versionName flutterVersionName

  manifestPlaceholders["PN_PROJECT_ID"] = "EXAMPLE"
  manifestPlaceholders["PN_PROJECT_CLIENT_KEY"] = "EXAMPLE"
  manifestPlaceholders["PN_APP_ID"] = "EXAMPLE"
}

Staying within your build.gradle file, you'll need to ensure that you're using version 11 of Java in both compileOptions and kotlinOptions, alongside enabling dataBinding.

// Example
compileOptions {
  sourceCompatibility JavaVersion.VERSION_11
  targetCompatibility JavaVersion.VERSION_11
}

kotlinOptions {
  jvmTarget = JavaVersion.VERSION_11 
}

dataBinding {
  enabled = true
}

Finally, for dependency management, within build.gradle you'll need to ensure that the repositories object in both buildscript and allprojects has maven { setUrl("https://jitpack.io") } present, such as is shown below.

// Example
buildscript {
  ...
  repositories {
      google()
      mavenCentral()
      maven { setUrl("https://jitpack.io") }  // Add this
  }

  dependencies {
      ...
  }
}


allprojects {
  repositories {
      google()
      mavenCentral()
      maven { setUrl("https://jitpack.io") }  // Add this
  }
}

...


iOS configuration

If you're building an iOS application with Flutter, this also entails a unique and iOS-specific configuration process. Before beginning, ensure your project meets the following prerequisites:

  • Xcode 15.0 or later.

  • iOS 14 or later.

With these requirements set, you'll need to open an exported iOS project and find ios/{project name}.xcworkspace.

At the root of your Xcode project, create a new file, ParticleNetwork-Info.plist. Ensure this is marked under "Target Membership."

Now, with a fresh ParticleNetwork-Info.plist file, go ahead and fill it in with the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>PROJECT_UUID</key>
	<string>YOUR_PROJECT_UUID</string>
	<key>PROJECT_CLIENT_KEY</key>
	<string>YOUR_PROJECT_CLIENT_KEY</string>
	<key>PROJECT_APP_UUID</key>
	<string>YOUR_PROJECT_APP_UUID</string>
</dict>
</plist>

Similar to the Android configuration, you'll need to fill in PROJECT_UUID (projectId), PROJECT_CLIENT_KEY, and PROJECT_APP_UUID (appId) with the corresponding values retrieved from the Particle dashboard.

Alternatively, to use Auth (deprecated), two more steps.

You'll need to head over to your AppDelegate.swift file to add an import of ParticleAuthService.

import ParticleAuthService

Additionally, within your application's application method (as shown below), you'll need to include a handler condition derived from ParticleAuthService.handleUrl. This should be as simple as a true return upon a truthy value of ParticleAuthService.handleUrl, and a super.application(app, open: url, options: options) return upon a falsy value.

override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
  if ParticleAuthService.handleUrl(url) {
      return true
  } else {
      return super.application(app, open: url, options: options)
  }
}

Wrapping up, you'll need to configure your application's scheme URL. To configure this, select your application from "TARGETS" under the "Info" section, then click "+" to add a URL type.

This should simply be set to "pn" + your projectId (retrieved and configured prior), resulting in a scheme URL that looks something like the following:

pn63bfa427-cf5f-4742-9ff1-e8f5a1b9828f

Finally, you'll need to edit your Podfile to ensure particle_auth is properly imported. Head over to the linked guide to complete this, if you haven't already.

📘

Another important note before continuing

Our SDK is a static library (XCFramework). When using the Particle Auth Flutter SDK, you'll need to specify that you're using a static framework through the following:

target 'Runner' do
  use_frameworks! :linkage => :static
  # user particle_auth_core
  pod "Thresh
  pod "ParticleMPCCore"
  pod "ParticleAuthCore"
  pod "AuthCoreAdapter"

  pod 'ParticleAuthService'
  pod 'ParticleNetworkBase'
  pod 'ConnectCommon'

	# Alternatively, to use particle_auth (deprecated)
	# pod 'ParticleAuthService'
  # pod 'ParticleNetworkBase'
end

Examples of utilization

Initialization

Before using the full extent of the SDK, you'll need to initialize it with init, passing in specific chain in which you intend to primary onboard to within Particle's Wallet-as-a-Service. This is represented as an object containing chain info (often derived from ChainInfo.{Chain}).

// set the project info, get it from dashboard.
ParticleInfo.set(projectId, clientKey);

// inititilze ParticleAuth and ParticleAuthCore.
ParticleAuth.init(ChainInfo.Ethereum, env);
ParticleAuthCore.init()

Login

Now that you've installed, configured, and initialized Particle Auth, you'll need to initiate a login and throw a social login prompt for a user to authenticate through. Post-login (through the menu obtained via the login), a user will have an account generated, thus unlocking the remaining SDK methods for interaction.

This is achieved and configured through ParticleAuthCore.connect or ParticleAuth.login(deprecated) . Once this method is called, the corresponding login popup will be thrown by requesting user authentication before returning to the application in a signed-in state.

ParticleAuth.login takes the following parameters:

  • loginType, the mechanism of social login to be thrown; such as email, Google, Twitter, etc:
  • LoginType.email
  • LoginType.phone
  • LoginType.google
  • LoginType.facebook
  • LoginType.apple
  • LoginType.twitter
  • LoginType.discord
  • LoginType.github
  • LoginType.twitch
  • LoginType.microsoft
  • LoginType.linkedin
  • LoginType.jwt
  • account, for predetermined/expected phone numbers or emails. This can be optimally used if you're using custom authentication with JWTs. It is also a required field with the expected JWT in question.
  • supportAuthTypes, the authentication types to be supported/shown in the authentication popup. The types listed here will be available as additional buttons in the generalized popup that shows within email- and phone-based logins, such as:
    • SupportAuthType.apple
    • SupportAuthType.google
    • SupportAuthType.facebook
    • SupportAuthType.discord
    • SupportAuthType.github
    • SupportAuthType.twitch
    • SupportAuthType.microsoft
    • SupportAuthType.linkedin
    • SupportAuthType.phone
    • SupportAuthType.email
    • SupportAuthType.twitter
  • authorization, an optional field in which a message can be passed for signature for added authorization.
List<SupportAuthType> supportAuthType = <SupportAuthType>[];
supportAuthType.add(SupportAuthType.all);

ParticleAuthCore.connect(LoginType.google, prompt: SocialLoginPrompt.select_account);

ParticleAuthCore.connect(LoginType.email, supportAuthTypes: SupportAuthType.values, prompt: SocialLoginPrompt.select_account);
  
// Alternatively, to use particle_auth (deprecated)

// Optional
final authorization = LoginAuthorization(messageHex, true);

ParticleAuth.login(
  LoginType.phone,
  "",
  supportAuthType,
  socialLoginPrompt,
  authorization
);

Is Login

There may be scenarios in which knowing whether a current session (a user) is currently logged in with Particle Auth or not is important. This is achieved through ParticleAuthCore.isConnected (server-side check), in particle_auth, which is deprecated, this is achieved through either ParticleAuth.isLogin (local check) or ParticleAuth.isLoginAsync (server-side check). These methods will return a Boolean based on the login state of the session in question.

await ParticleAuthCore.isConnected();


  
// Alternatively, to use particle_auth (deprecated)
await ParticleAuth.isLogin();

await ParticleAuth.isLoginAsync();

Logout

To exit an existing session (logging a user out), you can simply call ParticleAuthCore.disconnect . Alternatively, to use particle_auth (deprecated), you can simply call ParticleAuth.fastLogoutor ParticleAuth.logout.

awiat ParticleAuthCore.disconnect();

// Alternatively, to use particle_auth (deprecated)
await ParticleAuth.fastLogout();

Get Address

To retrieve the address, you can call Evm.getAddress or Solana.getAddress.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.getAddress, (EVM or Solana, depending on the active chain determined in prior initialization) retrieve the address of a given user/active session,

final address = await Evm.getAddress();
final address = await Solana.getAddress();

// Alternatively, to use particle_auth (deprecated)
final address = await ParticleAuth.getAddress();

Sign Message

To throw a standard message for signature (meaning a user will be prompted in-UI to sign a given string), you can call Evm.personalSign, This method on EVM requires a hexadecimal string, as shown below. Otherwise, on Solana, you can pass in a UTF-8/readable string.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.signMessage.

final messageHex = "0x${StringUtils.toHexString("Hello Particle")}";
String signature = await Evm.personalSign(messageHex);
String signature = await Evm.personalSignUnique(messageHex);

const message = "Hello Particle";
final signature = await Solana.signMessage(message);


// Alternatively, to use particle_auth (deprecated)
String signature = await ParticleAuth.signMessage(messageHex);
String signature = await ParticleAuth.signMessageUnique(messageHex);

Sign Transaction

This is a Solana-specific method for signing a transaction without sending it. Similar to message signing, this will prompt a signature in-UI with details about the transaction. Programmatically, the proposed transaction should be formatted as a (converted to a) base58 string. Passing in an object directly will not work in this case.

final signature = await Solana.signTransaction(transaction);

// Alternatively, to use particle_auth (deprecated)
final signature = await ParticleAuth.signTransaction(transaction);

Sign All Transactions

Following the aforementioned method, you can use Solana.signAllTransactions to propose a collection of Solana transactions for signature, rather than just a single transaction.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.signAllTransactions .


List<String> signatures = await Solana.signAllTransactions(transactions);

// Alternatively, to use particle_auth (deprecated)
List<String> signatures = await ParticleAuth.signAllTransactions(transactions);

Sign and Send Transaction

For more generalized transaction sending, Evm.sendTransactionand Solana.signAndSendTransaction will be the primary method used in virtually every scenario. This will propose a signature (on both EVM and Solana), and then immediately push it to the network once confirmed. For EVM, the transaction passed into ParticleAuth.signAndSendTransaction will need to be a hexadecimal string, while Solana requires a base58 string.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.signAndSendTransaction.

final signature = await Evm.sendTransaction(transaction);
final signature = await Solana.signAndSendTransaction(transaction);

// Alternatively, to use particle_auth (deprecated)
final signature = await ParticleAuth.signAndSendTransaction(transaction);

Sign Typed Data

Evm.signTypedData is an EVM-specific method for signing structured (typed) data. For more information on signTypedData, see the Web (JavaScript/TypeScript) page.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.signTypedData.

// your typed data is a json string
String typedDataHex = "0x${StringUtils.toHexString(typedData)}";

String signature = await Evm.signTypedData(typedDataHex);
String signature = await Evm.signTypedDataUnique(typedDataHex);

// Alternatively, to use particle_auth (deprecated)
String result =
        await ParticleAuth.signTypedData(typedDataHex, SignTypedDataVersion.v4);

Set Chain Info

If you'd like to set the chain being utilized (after initially defining this in init), you can call either ParticleAuth.setChainInfo (synchronous) or ParticleAuthCore.switchChain (asynchronous),ParticleAuth.setChainInfoAsync (asynchronous) and pass in a chain information object, often derived from {Chain}.{network}() or ChainInfo.{Chain}.

await ParticleAuth.setChainInfo(ChainInfo.EthereumGoerli);

await ParticleAuthCore.switchChain(ChainInfo.PolygonMumbai);


// Alternatively,  to use particle_auth (deprecated)
await ParticleAuth.setChainInfoAsync(ChainInfo.EthereumGoerli);

Get Chain Info

For the retrieval of the currently selected (primary) chain within an active session, you'll need to call ParticleAuth.getChainInfo. This returns a ChainInfo object containing:

  • name, the name of the chain in question (ex: Ethereum).
  • id, the ID of the chain in question (ex: 5).
  • network, the specific network corresponding to the chain ID (ex: Goerli)
final chainInfo = await ParticleAuth.getChainInfo();
int id = chainInfo.id;
String name = chainInfo.name;
String network = chainInfo.network;

Set Security Account Config

Another important component of integrating the Particle Auth SDK (Wallet-as-a-Service) is the (optional) security account requirements enforced upon application users. For all accounts on Particle, several security options are associated (such as a master password for a login-based non-recoverable password, payment password for a pin required upon transaction signatures, etc.)

Within the SDK, you can configure the frequency (or requirement) a user is asked to configure security settings. This is controlled with ParticleAuth.setSecurityAccountConfig and passing in a SecurityAccountConfig object with two parameters:

  1. promptSettingWhenSign, security account config prompts (default is 1).
  2. promptMasterPasswordSettingWhenLogin, master password prompts (default is 0).
  • 0 means a prompt is never shown requesting this setting.
  • 1 means a prompt is shown only upon the first startup.
  • 2 means a prompt is shown every time.
  • 3 means force set payment password before sign.
final config = SecurityAccountConfig(1, 2);
ParticleAuth.setSecurityAccountConfig(config);

Open Account and Security Page

Following the above, if you'd like to force the opening of account/security settings (in-UI), you can do so with ParticleAuth.openAccountAndSecurity.

await ParticleAuth.openAccountAndSecurity();

Open Web Wallet (deprecated in particle_auth_core)

Alternatively, to use ParticleAuth.openWebWallet in particle_auth (deprecated).

If you'd like to open the complete wallet UI (for most chains, this includes swaps, bridging, etc., alongside various wallet settings) in a standalone web interface with specific configurations, then you can call ParticleAuth.openWebWallet. For more information on the specific configurations possible here, see the Wallet SDK page.

String webConfig =
    '''
     {
        "supportAddToken": false,
        "supportChains": [{
            "id": 1,
            "name": "Ethereum"
          },
          {
            "id": 5,
            "name": "Ethereum"
          }
        ]
      }
    ''';
    
ParticleAuth.openWebWallet(webConfig);  

Has Master Password, Payment Password, Security Account

Similarly to the isLogin function covered prior, there are various scenarios in which knowing whether or not a user has specific security settings enabled may be useful. In the case of the Particle Auth Flutter SDK, this can happen in one of two ways:

With the built-in ParticleAuthCore.hasMasterPassword, ParticleAuthCore.hasPaymentPassword, and ParticleAuthCore.changeMasterPassword methods.

Alternatively, to use particle_auth (deprecated), you can call ParticleAuth.hasMasterPassword, ParticleAuth.hasPaymentPassword,ParticleAuth.hasSecurityAccount and ParticleAuth.getSecurityAccount methods.


await ParticleAuthCore.hasMasterPassword();
await ParticleAuthCore.hasPaymentPassword();
await ParticleAuthCore.changeMasterPassword();


// Alternatively,  to use particle_auth (deprecated)
await ParticleAuth.hasMasterPassword();
await ParticleAuth.hasPaymentPassword();
await ParticleAuth.hasSecurityAccount();

final securityAccount = await ParticleAuth.getSecurityAccount();

EvmService utilization examples

In addition to ParticleAuth for authentication and interaction with Particle's Wallet-as-a-Service, the Flutter SDK also includes a class, EvmService, for general interaction with EVM chains.

Read Contract

EvmService.readContract allows you to execute a read-only contract call defined by a specific method and set of parameters. This requires a corresponding ABI, contract address, and requester public address.

String publicAddress = "your public address";
String contractAddress = "your contract address"; 
String methodName ="mint"; // ex: balanceOf, mint
List<Object> parameters = <Object>["1"];

// ex: [{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"}]  
const abiJsonString = null;

final result = await EvmService.readContract(publicAddress, contractAddress, methodName, parameters, abiJsonString);

Create Transaction

EvmService.createTransaction facilitates the construction of a transaction object derived from the standard from, to (receiver in this example), amount (value), and data fields. This transaction, once constructed with EvmService.createTransaction, can be passed for in-UI proposal with ParticleAuth.signAndSendTransaction.

String from = "your public address";
String receiver = "to address"  
String contractAddress = "contract address"
BigInt amount = "some amount";
String to = contractAddress;
final erc20Resp = 
    await EvmService.erc20Transfer(contractAddress, receiver, amount);
// Example of data generation
final data = jsonDecode(erc20Resp)["result"]; // 0x for native transfers

final transaction = await EvmService.createTransaction(
    from, data, BigInt.from(0), to,
    gasFeeLevel: GasFeeLevel.high);

Estimate Gas

Given a standard transaction structure (detached set of values, as shown below), gas estimations can be ran to simulate and retrieve the volume of gas to be consumed by a specified transaction (wrapper for eth_estimateGas). This is done through EvmService.evmEstimateGas.

final result = await EvmService.evmEstimateGas(from, to, value, data);

Get Suggested Gas Fees

To retrieve categorized gas price suggestions (3 categories scaling from low to high) based upon current network conditions, you can call EvmService.suggestedGasFees.

await EvmService.suggestedGasFees();

Get Tokens and NFTs

EvmService also extends to Data API methods such as getTokensAndNFTs, which returns a highly detailed JSON list of ERC20 tokens and ERC721 NFTs belonging to a specified address. This is accessible through EvmService.getTokensAndNFTs, passing in the public address to retrieve the tokens and NFTs of.

await EvmService.getTokensAndNFTs(publicAddress);

Get Transactions by Address

Similar to the former method, EvmService.getTransactionsByAddress enables the retrieval of a detailed JSON response containing a complete list of transactions involving a specified address.

await EvmService.getTransactionsByAddress(publicAddress);

Get price

To retrieve token price based upon current network conditions, you can call EvmService.getPrice.

 await EvmService.getPrice(tokenAddresses, currencies);

Basic rpc method

Call any basic EVM rpc method through EvmService.rpc

await EvmService.rpc(method, params);

SolanaService utilization examples

In addition to ParticleAuth for authentication and interaction with Particle's Wallet-as-a-Service, the Flutter SDK also includes a class, SolanaService, for general interaction with Solana chains.

Get Tokens and NFTs

SolanaService also extends to Data API methods such as getTokensAndNFTs, which returns a highly detailed JSON list of SPL tokens and NFTs belonging to a specified address. This is accessible through SolanaService.getTokensAndNFTs, passing in the public address to retrieve the tokens and NFTs of.

await SolanaService.getTokensAndNFTs(publicAddress, true);

Serialize Transactions

SolanaService.serializeSolTransaction facilitates the construction of a SOL transaction object,

SolanaService.serializeSplTokenTransaction facilitates the construction of a Spl-token transaction object,

SolanaService.serializeWSolTokenTransaction facilitates the construction of a unwrap wsol transaction object.

These transactions, once constructed , can be passed for in-UI proposal with ParticleAuth.signAndSendTransaction.

final transaction = SerializeSOLTransaction();  
transaction.lamports = TestAccount.solana.amount.toInt();  
transaction.receiver = TestAccount.solana.publicAddress;  
transaction.sender = publicAddress;

final result = await SolanaService.serializeSolTransaction(transaction);
final serializedTransaction = result["transaction"]["serialized"];
final transaction = SerializeSplTokenTransaction();
transaction.amount = TestAccount.solana.amount.toInt();
transaction.receiver = TestAccount.solana.publicAddress;
transaction.mint = TestAccount.solana.tokenContractAddress;
transaction.sender = publicAddress;

final result = await SolanaService.serializeSplTokenTransaction(transaction);
final serializedTransaction = result["transaction"]["serialized"];
final transaction = SerializeWSOLTransaction();
transaction.address = publicAddress;

final result = await SolanaService.serializeWSolTokenTransaction(transaction);
final serializedTransaction = result["transaction"]["serialized"];

Get price

To retrieve token price based upon current network conditions, you can call SolanaService.getPrice.

 await SolanaService.getPrice(tokenAddresses, currencies);

Get transactions by address

To retrieve transactions from a address, you can call SolanaService.getTransactionsByAddress.

await SolanaService.getTransactionsByAddress(address);

Get token by token address

To obtain the balance of a specified token at a specified address, you can call SolanaService.getTokenByTokenAddresses

await SolanaService.getTokenByTokenAddresses(address, tokenAddresses);

Basic rpc method

Call any basic Solana rpc method through SolanaService.rpc

await SolanaService.rpc(method, params);

Master reference

For a direct, raw view into every method provided through ParticleAuth, below is a table containing every relevant method alongside specific parameters and a short description. For methods listed but not covered in the above examples, live implementation often mimics the common structure covered throughout this document.

ClassMethodsParameters (* indicates optional)
ParticleAuthinitchainInfo, env
ParticleAuthloginloginType, account, supportAuthTypes, socialLoginPrompt, authorization
ParticleAuthisLogin
ParticleAuthisLoginAsync
ParticleAuthlogout
ParticleAuthfastLogout
ParticleAuthgetAddress
ParticleAuthgetUserInfo
ParticleAuthsignMessagemessage
ParticleAuthsignMessageUniquemessage
ParticleAuthsignTransactiontransaction
ParticleAuthsignAllTransactionstransactions
ParticleAuthsignAndSendTransactiontransaction, feeMode
ParticleAuthbatchSendTransactionstransactions, feeMode
ParticleAuthsignTypedDatatypedData, version
ParticleAuthsetChainInfochainInfo
ParticleAuthsetChainInfoAsyncchainInfo
ParticleAuthgetChainInfo
ParticleAuthopenWebWalletjsonStringConfig
ParticleAuthsetWebAuthConfigdisplayWallet, appearance
ParticleAuthsetAppearanceappearance
ParticleAuthsetSecurityAccountConfigconfig
ParticleAuthopenAccountAndSecurity
ParticleAuthsetModalPresentStylemodalPresentStyle
ParticleAuthsetMediumScreenisMediumScreen
ParticleAuthsetLanguagelanguage
ParticleAuthgetLanguage
ParticleAuthhasMasterPassword
ParticleAuthhasPaymentPassword
ParticleAuthhasSecurityAccount
ParticleAuthgetSecurityAccount
ParticleAuthsetFiatCoinfiatCoin