Overview

This guide outlines how to implement social login (OAuth) with the ParaSwift SDK. It covers setup, authentication flow, and handling both new and existing user scenarios with providers like Google, Apple, and Discord.

Prerequisites

Prerequisites

To use Para, you need an API key. This key authenticates your requests to Para services and is essential for integration.

Don’t have an API key yet? Request access to the Developer Portal to create API keys, manage billing, teams, and more.

You must have the ParaSwift SDK installed and configured in your project. If you haven’t done this yet, please refer to our Quick Start Guide.

Environment Setup

Before implementing social login, ensure your environment is properly configured:

  1. Add the webAuthenticationSession environment value in your view
  2. Add the authorizationController environment value for handling passkey operations after social login
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
@Environment(\.authorizationController) private var authorizationController

Implementing Social Login

Setup

Create a view that will handle the social login process:

import SwiftUI
import ParaSwift
import AuthenticationServices

struct SocialLoginView: View {
    @EnvironmentObject var paraManager: ParaManager
    
    @Environment(\.webAuthenticationSession) private var webAuthenticationSession
    @Environment(\.authorizationController) private var authorizationController
    
    @State private var email = ""
    @State private var error: Error?
}

Initiating OAuth Authentication

To begin the OAuth flow with a specific provider, call the handleOAuth method. This method handles the complete OAuth flow including user authentication, Para account lookup/creation, and passkey setup for new users:

private func login(provider: OAuthProvider) {
    Task {
        do {
            let result = await paraManager.handleOAuth(
                provider: provider,
                webAuthenticationSession: webAuthenticationSession,
                authorizationController: authorizationController
            )
            
            if result.success {
                // OAuth flow completed successfully
                // User is now logged in and wallets are available
                // Navigate to authenticated area of your app
                navigationState = .home
            } else {
                // Handle OAuth error
                self.error = ParaError.error(result.errorMessage ?? "OAuth login failed")
                self.showError = true
            }
        } catch {
            self.error = error
            self.showError = true
        }
    }
}

The handleOAuth method:

  • Authenticates the user with the OAuth provider
  • Checks if a Para account exists for the user
  • For new users: creates a Para account and sets up a passkey automatically
  • For existing users: logs them in directly
  • Returns a success/failure result with any error message

Creating Social Login Buttons

Here’s an example of how to create buttons for different OAuth providers:

var body: some View {
    VStack {
        // Google Login Button
        Button {
            login(provider: .google)
        } label: {
            HStack(spacing: 15) {
                Image("google")
                    .resizable()
                    .frame(width: 24, height: 24)
                Text("Login with Google")
                    .fontWeight(.semibold)
            }
            .frame(maxWidth: .infinity)
        }
        .buttonStyle(.borderedProminent)
        .controlSize(.large)
        .tint(.primary)
        .foregroundStyle(.background)
        
        // Discord Login Button
        Button {
            login(provider: .discord)
        } label: {
            HStack(spacing: 15) {
                Image("discord")
                    .resizable()
                    .frame(width: 24, height: 20)
                Text("Login with Discord")
                    .fontWeight(.semibold)
            }
            .frame(maxWidth: .infinity)
        }
        .buttonStyle(.borderedProminent)
        .controlSize(.large)
        .tint(Color(uiColor: UIColor(rgb: 0x5865F2)))
        
        // Apple Login Button
        Button {
            login(provider: .apple)
        } label: {
            HStack(spacing: 15) {
                Image("apple")
                    .resizable()
                    .frame(width: 24, height: 24)
                Text("Login with Apple")
                    .fontWeight(.semibold)
            }
            .frame(maxWidth: .infinity)
        }
        .buttonStyle(.borderedProminent)
        .controlSize(.large)
    }
    .padding()
}

Available OAuth Providers

The ParaSwift SDK supports the following OAuth providers:

  • Google (.google)
  • Apple (.apple)
  • Discord (.discord)

Complete Example

Here’s a complete example of a social login view:

import SwiftUI
import ParaSwift
import AuthenticationServices

struct SocialLoginView: View {
    @EnvironmentObject var paraManager: ParaManager
    @State private var navigationState: NavigationState = .idle
    
    @Environment(\.webAuthenticationSession) private var webAuthenticationSession
    @Environment(\.authorizationController) private var authorizationController
    
    @State private var email = ""
    @State private var error: Error?
    @State private var showError = false
    
    enum NavigationState {
        case idle
        case home
    }
    
    private func login(provider: OAuthProvider) {
        Task {
            let result = await paraManager.handleOAuth(
                provider: provider,
                webAuthenticationSession: webAuthenticationSession,
                authorizationController: authorizationController
            )
            
            if result.success {
                // OAuth flow completed successfully
                // User is now logged in and wallets are available
                navigationState = .home
            } else {
                // Handle OAuth error
                self.error = ParaError.error(result.errorMessage ?? "OAuth login failed")
                self.showError = true
            }
        }
    }
    
    var body: some View {
        VStack {
            Button {
                login(provider: .google)
            } label: {
                HStack(spacing: 15) {
                    Image("google")
                        .resizable()
                        .frame(width: 24, height: 24)
                    Text("Login with Google")
                        .fontWeight(.semibold)
                }
                .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .controlSize(.large)
            .tint(.primary)
            .foregroundStyle(.background)
            
            Button {
                login(provider: .discord)
            } label: {
                HStack(spacing: 15) {
                    Image("discord")
                        .resizable()
                        .frame(width: 24, height: 20)
                    Text("Login with Discord")
                        .fontWeight(.semibold)
                }
                .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .controlSize(.large)
            .tint(Color(uiColor: UIColor(rgb: 0x5865F2)))
            
            Button {
                login(provider: .apple)
            } label: {
                HStack(spacing: 15) {
                    Image("apple")
                        .resizable()
                        .frame(width: 24, height: 24)
                    Text("Login with Apple")
                        .fontWeight(.semibold)
                }
                .frame(maxWidth: .infinity)
            }
            .buttonStyle(.borderedProminent)
            .controlSize(.large)
        }
        .alert("Connection Error", isPresented: $showError) {
            Button("OK", role: .cancel) { }
        } message: {
            Text(error?.localizedDescription ?? "Unknown error occurred")
        }
        .navigationDestination(isPresented: Binding(
            get: { navigationState == .home },
            set: { if !$0 { navigationState = .idle } }
        )) {
            HomeView()
        }
        .padding()
        .navigationTitle("Social Login")
    }
}

// Helper extension for UIColor from hex
extension UIColor {
    convenience init(rgb: UInt) {
        self.init(
            red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgb & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    }
}

Next Steps

After implementing social login, you might want to:

  1. Set up email verification for new users
  2. Implement secure storage for session management
  3. Add biometric authentication as an additional security layer