Particle Auth for iOS

The Particle Auth iOS SDK is the primary means of integrating Particle’s Wallet-as-a-Service within applications on iOS. From initialization and configuration to onboarding and account utilization, this SDK acts as the master library for interacting with Particle on iOS.

The Particle Auth iOS SDK follows configuration and implementation mechanisms similar to the Particle Auth Android SDK. The specifics of integration, along with several examples, will be covered below.

Getting Started

Implementation of the Particle Auth iOS SDK only takes a few lines of code, although before getting to that point, you’ll need to meet a few key prerequisites in mind to ensure compatibility.

Prerequisites

  • Xcode 15.0 or later.
  • CocoaPods 1.14.3 or higher.
  • Your project must target these platform versions or later:
    • iOS 14.

Configuration

To begin the initialization process, you must head over to the Particle dashboard and create a project alongside a corresponding application.

These will control specific customizations, statistics, and more for your instance of Particle’s Wallet-as-a-Service. After creating an application, you’ll need to retrieve three key values: projectId, clientKey, and appId. We’ll be using these down the road.

Follow the quickstart tutorial to set up a project and find the required keys: Create a new project.

Installation

Now that you’ve created a project and an application within the Particle dashboard, you’ll need to go ahead and install the Particle Auth SDK using CocoaPads (assuming you meet the previously mentioned minimum version requirements).

  1. If you don’t already have a Podfile, create one from the root of your project directory with:

    Terminal
    pod init
    
  2. Within the newly created Podfile, add the ParticleAuthCore, ParticleMPCCore, and Thresh pod.

    Podfile
    pod 'ParticleAuthCore'
    pod 'ParticleMPCCore'
    pod 'Thresh'
    
  3. Install the pods, then open your .xcworkspace file to see the project in Xcode.

    Terminal
    pod install --repo-update
    open your-project.xcworkspace
    

For release updates, subscribe to the GitHub repository.

Podfile Configuration

Additionally, you’ll need to ensure that your resulting Podfile is properly configured and contains a snippet similar to the example below.

Podfile
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end
end

Initialization

Now that you’ve configured your Particle dashboard, installed the SDK, and configured a Podfile, it’s time to initialize the SDK with the aforementioned projectId, clientKey, and appId retrieved from the Particle dashboard.

  1. Create a ParticleNetwork-Info.plist file from the root of your corresponding Xcode project.

  2. Paste the following text into this file:

    ParticleNetwork-Info.plist
    <?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>
    
  3. Replace the placeholders with the values retrieved from your project and application within the Particle dashboard.

  4. Import the ParticleNetworkBase module in your AppDelegate.swift file.

    AppDelegate.swift
    import ParticleNetworkBase
    
  5. Initialize the ParticleNetwork service, which is typically located within your app’s application:didFinishLaunchingWithOptions method:

    AppDelegate.swift
    // Set a primary network, derived from ChainInfo
    // For release, this can be set to DevEnvironment.production
    ParticleNetwork.initialize(config: .init(chainInfo: .ethereum, devEnv: .debug))
    
  6. Add Privacy - Face ID Usage Description to your info.plist file, head over to your Info.plist file and include the following snippet:

    Info.plist
    <key>NSFaceIDUsageDescription</key>
      <string>We use Face ID for secure access to the app.</string>
    

Switch Chain

To switch the used chain after initial configuration, auth.switchChain is used. This enables asynchronous switching. Similar to the initial configuration, chain information derived from ParticleNetwork.ChainInfo can be passed as the primary parameter, determining the destination chain.

FieldTypeDescription
chainInfoChainInfoA chainInfo object, can be derived from ParticleNetwork.ChainInfo.
let auth = Auth()
let result = try await auth.switchChain(chainInfo: .ethereum)

// For switching chains synchronously, without checking login status
ParticleNetwork.setChainInfo(.ethereum)

Examples of utilization

Connect

auth.connect is the main mechanism for facilitating login (account creation or sign in) with Particle’s Wallet-as-a-Service. Specifically, five key parameters are available within auth.connect:

FieldTypeDescription
typeLoginTypeThe specific social login to be used. This can be either .email, .phone, .google, .apple, .jwt, .facebook, .twitter, .discord, .github, .twitch, .microsoft or linkedin.
accountString?(Optional) When type is set to either .email, .phone, or .jwt, you can use the account parameter to pass in an expected email, phone number, or JWT. This is optional for the former two, but required for .jwt. When passing a phone number, it must be in E.164 format.
codeString?(Optional) When type is set to either .email pr .phone, you can use the code parameter to pass the verification code.
socialLoginPromptSocialLoginPrompt?(Optional) Changes what the OAuth provider prompts a user to do; either .none, .consent, or .select_account. Only Google, Discord and Microsoft support it.
You can use your existing user base or authentication method with Particle Auth through JWT. This way, your users can still log in with their current accounts. Click here to learn how to configure jwt.
// Connect with Google
let userInfo = try await auth.connect(type: .google, socialLoginPrompt: .selectAccount)

// Send verification code to email or phone number, the phone number must be in E.164 format.
var result = try await auth.sendEmailCode(email: "user@example.com")
var result = try await auth.sendPhoneCode(email: "+11234567890")

// Connect with email or phone, the phone number must be in E.164 format.
let userInfo = try await auth.connect(type: .email, account: "user@example.com", code: "xxxxxx")
let userInfo = try await auth.connect(type: .phone, account: "+11234567890", code: "xxxxxx")

// Connect with JWT
let jwt = "json web token"
let userInfo = try await auth.connect(type: .jwt, account: jwt)

auth.presentLoginPage is another mechanism for facilitating login (account creation or sign in) with Particle’s Wallet-as-a-Service. Upon calling this method, an authentication UI will be thrown, and the user will be asked to sign in with a specified login method. Specifically, five key parameters are available within auth.presentLoginPage:

FieldTypeDescription
typeLoginTypeThe specific social login to be used. This can be either .email, .phone, .google, .apple, .jwt, .facebook, .twitter, .discord, .github, .twitch, .microsoft or linkedin.
accountString?(Optional) When type is set to either .email, .phone, or .jwt, you can use the account parameter to pass in an expected email, phone number, or JWT. This is optional for the former two, but required for .jwt. When passing a phone number, it must be in E.164 format.
supportAuthTypeode[SupportAuthType]The methods of authentication visible on the authentication popup UI. By default, this will be exclusive to the chosen social login method, although by passing in additional types, you can expand the UI to include the ability to login with those as an alternative to type.
socialLoginPromptSocialLoginPrompt?(Optional) Changes what the OAuth provider prompts a user to do; either .none, .consent, or .select_account. Only Google, Discord and Microsoft support it.
configLoginPageConfig?(Optional) To customize the UI page, contains project name, icon and description.
var userInfo = try await auth.presentLoginPage(type: type, account: text, socialLoginPrompt: .selectAccount, config: config)

After connect is successful, detailed user information can be retrieved by calling auth.getUserInfo.

Is Connected

To check the user’s login status, auth.getUserInfo() != nil returns a Boolean based upon the current state of a session (whether or not a user is currently logged into an account). Additionally, an asynchronous method, auth.isConnected can be called and subscribed to, returning userInfo upon a status of true.

// Local
let result = auth.getUserInfo() != nil
// Server side
let result = try await auth.isConnected()

Disconnect

auth.disconnect will simply log a user out of their existing session, assuming they’re logged in.

let result = try await auth.disconnect()

UserInfo and Address Retrieval (post-login)

Once a user has logged in, you’ll have access to various methods such as auth.getUserInfo and auth.evm.getAddressto retrieve specific user details. The getUserInfo response will, by default, include both an associated EVM and Solana address, while auth.evm.getAddress will return an EVM address, auth.solana.getAddress will return a Solana address.

auth.getUserInfo()
auth.evm.getAddress()
auth.solana.getAddress()

Signatures

Once ParticleNetwork has been initialized and a user has successfully logged in, signatures can be proposed for confirmation through a popup

EVM

Sign Message (EIP191)

To request an EIP191 signature from a user’s embedded wallet, you can use either the auth.evm.personalSign or auth.evm.personalSignUnique method. If you need the same message to return a unique signature each time, use the auth.evm.personalSignUnique method. Otherwise, the auth.evm.personalSign method is generally recommended.

FieldTypeDescription
messageStringEither a hexadecimal string starting with ‘0x’ or a human-readable string is required.
chainInfoChainInfo?(Optional) Default is current chainInfo, the specific chain selected
let result = try await auth.evm.personalSign("This is the message that is being signed", chainInfo: nil)
let result = try await auth.evm.personalSignUnique("This is the message that is being signed", chainInfo: nil)

Sign Typed Data V4 (EIP712)

To request an EIP712 signature from a user’s embedded wallet, you can use either the auth.evm.signTypedData or auth.evm.signTypedDataUnique method. If you need the same message to return a unique signature each time, use the auth.evm.signTypedDataUnique method. Otherwise, the auth.evm.signTypedData method is generally recommended.

FieldTypeDescription
messageStringEither a hexadecimal string starting with “0x” or a JSON string is required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign
let result = try await auth.evm.signTypedData(message, chainInfo: nil)
let result = try await auth.evm.signTypedDataUnique(message, chainInfo: nil)

Transaction

To send a transaction from a user’s embedded wallet, you can use auth.evm.sendTransaction.

FieldTypeDescription
transactionStringA hexadecimal string starting with “0x” is required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign and send
let result = try await auth.evm.sendTransaction(transaction, chainInfo: nil)

Solana

Signing Messages

To request a signature from a user’s embedded wallet, you can use auth.solana.signMessage.

FieldTypeDescription
messageStringA base58 formatted string is required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign
let message = Base58.encode("This is the message that is being signed".data(using: .utf8)!)
let result = try await auth.solana.signMessage(message, chainInfo: nil)

Transaction

To send a transaction from a user’s embedded wallet, you can use auth.solana.signAndSendTransaction.

FieldTypeDescription
transactionStringA base58 formatted string is required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign and send
let result = try await auth.solana.signAndSendTransaction(transaction, chainInfo: nil)

To sign a transaction from a user’s embedded wallet, you can use auth.solana.signTransaction.

FieldTypeDescription
transactionStringA base58 formatted string is required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign
let result = try await auth.solana.signTransaction(transaction, chainInfo: nil)

To sign multi transactions from a user’s embedded wallet, you can use auth.solana.signAllTransactions.

FieldTypeDescription
transactionsStringBase58 formatted strings are required.
chainInfoChainInfo?(Optional) default is current chainInfo, the specific use which chain to sign
let result = try await auth.solana.signAllTransactions(transactions, chainInfo: nil)

You can create en EVM transaction with class TxData or FeeMarketEIP1559TxData, also you can use another SDK ParticleWalletAPI to create transaction, you can reference the examples from Wallet SDK reference, all the rpc methods are defined in ParticleWalletAPI.


Open Account and Security

If you’d like to force the “Account and Security” options to be opened on-screen (from which you can control payment passwords, additional accounts, and so on), then you can call auth.openAccountAndSecurity. Upon calling this method, a popup allowing the user to control security settings will appear.

try auth.openAccountAndSecurity()

Set Security Account Config

Within the security settings, specific popups can be set to display upon confirmation or wallet UI entrance. These popups include promptSettingWhenSign, which refers to payment (signature) passwords, and promptMasterPasswordSettingWhenLogin, which refers to a login-based master password.

By default, promptSettingWhenSign is set to 1, which will show the prompt upon the first signature a given account conducts. If it’s set to 0, it will never be shown; if it’s set to 2, it will be shown upon every signature confirmation, if it’s set to 3, it will be forced to set payment password.

This same logic applies to promptMasterPasswordSettingWhenLogin, which by default is set to 0.

ParticleNetwork.setSecurityAccountConfig(config:
  .init(promptSettingWhenSign: 1, promptMasterPasswordSettingWhenLogin: 2))

let securityAccountConfig = PartilceNetwork.getSecurityAccountConfig()

Master Password and Payment Password

User can set master password and payment password to protect assets, call auth.changeMasterPassword to set or change master password, call auth.openAccountAndSecurity() to set or change payment password.

// Check if user has a master password set
let result = try auth.hasMasterPassword()
// Set or change master password
let result = try await auth.changeMasterPassword()

// Check if user has a payment password set
let result = try auth.hasPaymentPassword()
// Open a general account security page
let result = try auth.openAccountAndSecurity()

Set Appearance

You can forcibly set a specific appearance to be used within the UI using ParticleNetwork.setAppearance. By default, it will follow current system setting.

FieldTypeDescription
appearanceUIUserInterfaceStyleThe specific appearance to be used. This can be either .unspefified, .dark, .light.
// This is the default setting, auto
ParticleNetwork.setAppearance(.unspecified)
// Dark mode
ParticleNetwork.setAppearance(.dark)
// Light mode
ParticleNetwork.setAppearance(.light)

Set and Get Language

You can forcibly set a specific language to be used within the UI using ParticleNetwork.setLanguage, with retrieval of the current active language facilitated by ParticleNetwork.getLanguage. By default, this is set to English.

FieldTypeDescription
languageLanguageThe specific language to be used. This can be either .en, .ja, .zh_hans, .zh_hant, .ko.
ParticleNetwork.setLanguage(Language.en)

ParticleNetwork.getLanguage()

Set Custom UI JSON string

// Configure a custom UI through passing a JSON string
let jsonString = "Your custom UI json string, keys should be the same with customUIConfig.json in demo"
Auth.loadCustomUIJsonString(jsonString)

Set FiatCoin

You can set a specific fiat currency to be used within the UI using ParticleNetwork.setFiatCoin, with retrieval of the current active language facilitated by ParticleNetwork.getFiatCoin. By default, this is set to USD.

FieldTypeDescription
fiatCoinFiatCoinThe specific fiat currency in which value is denominated. This can be either .usd, .cny, .jpy, .hkd, .inr, .krw.
ParticleNetwork.setFiatCoin(FiatCoin.usd)

ParticleNetwork.getFiatCoin()

Enable Blind Signing

Silently sign messages/transactions, this switch will work if the following conditions are met:

  1. Your account is connected with JWT
  2. Your account hasn’t set a payment password
  3. SecurityAccountConfig.promptSettingWhenSign is 0, you can call ParticleNetwork.setSecurityAccountConfig to update its value.
// Enable (or disable) blind signing
Auth.setBlindEnable(true)
// Retrieve whether or not blind signing is enabled
let result = Auth.getBlindEnable()