Step-by-step guide for integrating the Para Swift SDK into your iOS application
The Para Swift SDK enables you to integrate secure wallet features including creation, passkey-based authentication, and transaction signing into your iOS applications. This guide covers all necessary steps from installation to implementing authentication flows.
Provide your Team ID + Bundle ID to Para, e.g. A1B2C3D4E5.com.example.yourapp
Without properly registering your domain with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
Beta Testing Credentials In the BETA Environment, you can use any email ending in @test.getpara.com (like
dev@test.getpara.com) or US phone numbers (+1) in the format (area code)-555-xxxx (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
First, you need to initialize the Para manager in your app. Below is an example of initializing the SDK in a SwiftUI application:
Copy
Ask AI
import SwiftUIimport ParaSwift@mainstruct ExampleApp: App { @StateObject private var paraManager: ParaManager @StateObject private var appRootManager = AppRootManager() init() { // Simple configuration with API key and environment let config = ParaConfig( apiKey: "YOUR_API_KEY_HERE", environment: .sandbox // or .beta, .prod ) _paraManager = StateObject(wrappedValue: ParaManager( environment: config.environment, apiKey: config.apiKey, appScheme: "paraswift" // Your app's URL scheme for deep linking )) } var body: some Scene { WindowGroup { ContentView() .environmentObject(paraManager) .environmentObject(appRootManager) } }}
The appScheme parameter is used for deep linking with external wallets like MetaMask. Make sure to configure your appβs URL scheme in your Info.plist to match this value.
Security Best Practice: Never hardcode your API key in production code. Instead, use environment variables or build configuration:
Add PARA_API_KEY to your schemeβs environment variables or build settings
Access it securely:
Copy
Ask AI
let apiKey = ProcessInfo.processInfo.environment["PARA_API_KEY"] ?? ""
Para provides a unified authentication experience that supports email, phone, and social login methods. The SDK automatically determines whether a user is new or existing and guides you through the appropriate flow.
The recommended approach is to create a single authentication view that handles all authentication methods together. This provides users with all authentication options in one place.
The unified authentication flow automatically detects whether the input is an email or phone number and handles it accordingly.
1
Handle Email/Phone Submission
Initiate authentication with email or phone:
Copy
Ask AI
// Determine if input is email or phonelet auth: Authif userInput.contains("@") { auth = .email(userInput)} else { auth = .phone(userInput) // Include country code}// SDK call: Initiate authenticationlet authState = try await paraManager.initiateAuthFlow(auth: auth)// Handle the result based on stageswitch authState.stage {case .verify: // New user - needs verification // Show OTP input UIcase .login: // Existing user - complete login try await paraManager.handleLogin( authState: authState, authorizationController: authorizationController, webAuthenticationSession: webAuthenticationSession )case .signup: // Handle signup after verification}
2
Handle OTP Verification
For new users who need verification, handle the OTP flow:
Copy
Ask AI
// After user enters the verification codelet verificationCode = "123456" // Get from user inputdo { // Submit verification code let verifiedState = try await paraManager.handleVerificationCode( verificationCode: verificationCode ) // Complete signup with passkey (preferred) or password let method: ParaManager.SignupMethod = paraManager.isSignupMethodAvailable( method: .passkey, authState: verifiedState ) ? .passkey : .password try await paraManager.handleSignup( authState: verifiedState, method: method, authorizationController: authorizationController, webAuthenticationSession: webAuthenticationSession ) // User is now signed up and authenticated} catch { // Handle error}
The unified authentication flow automatically detects whether the input is an email or phone number and handles it accordingly.
1
Handle Email/Phone Submission
Initiate authentication with email or phone:
Copy
Ask AI
// Determine if input is email or phonelet auth: Authif userInput.contains("@") { auth = .email(userInput)} else { auth = .phone(userInput) // Include country code}// SDK call: Initiate authenticationlet authState = try await paraManager.initiateAuthFlow(auth: auth)// Handle the result based on stageswitch authState.stage {case .verify: // New user - needs verification // Show OTP input UIcase .login: // Existing user - complete login try await paraManager.handleLogin( authState: authState, authorizationController: authorizationController, webAuthenticationSession: webAuthenticationSession )case .signup: // Handle signup after verification}
2
Handle OTP Verification
For new users who need verification, handle the OTP flow:
Copy
Ask AI
// After user enters the verification codelet verificationCode = "123456" // Get from user inputdo { // Submit verification code let verifiedState = try await paraManager.handleVerificationCode( verificationCode: verificationCode ) // Complete signup with passkey (preferred) or password let method: ParaManager.SignupMethod = paraManager.isSignupMethodAvailable( method: .passkey, authState: verifiedState ) ? .passkey : .password try await paraManager.handleSignup( authState: verifiedState, method: method, authorizationController: authorizationController, webAuthenticationSession: webAuthenticationSession ) // User is now signed up and authenticated} catch { // Handle error}
Social login is integrated directly into the unified authentication view. Users can authenticate with Google, Apple, or Discord.
1
Handle Social Login
Implement the social login handler:
Copy
Ask AI
private func handleSocialLogin(_ provider: OAuthProvider) { Task { do { let result = await paraManager.handleOAuth( provider: provider, webAuthenticationSession: webAuthenticationSession, authorizationController: authorizationController ) if result.success { // User successfully authenticated appRootManager.setAuthenticated(true) } else { // Handle error print(result.errorMessage ?? "OAuth login failed") } } catch { // Handle error } }}
2
Social Login Buttons
Add buttons for each OAuth provider:
Copy
Ask AI
// Google LoginButton("Continue with Google") { handleSocialLogin(.google)}// Apple LoginButton("Continue with Apple") { handleSocialLogin(.apple)}// Discord LoginButton("Continue with Discord") { handleSocialLogin(.discord)}
After initial setup, users can log in using their email or phone with the same authentication flow:
Copy
Ask AI
// Login with emaillet authState = try await paraManager.initiateAuthFlow(auth: .email(userEmail))// Since the user exists, authState.stage will be .loginif authState.stage == .login { try await paraManager.handleLogin( authState: authState, authorizationController: authorizationController, webAuthenticationSession: webAuthenticationSession ) // User is now logged in}
Alternatively, you can use direct passkey login if you know the user has set up passkeys:
Copy
Ask AI
// Direct passkey login (will show all available passkeys if email/phone not provided)try await paraManager.loginWithPasskey( authorizationController: authorizationController, email: userEmail, // Optional - helps filter passkeys phone: nil)
This will prompt the user for Face ID or Touch ID verification before granting access to their wallets.
let isLoggedIn = await paraManager.isFullyLoggedIn()if isLoggedIn { // User is authenticated, proceed to main app flow} else { // Show login/signup UI}