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:
- Add the
webAuthenticationSession
environment value in your view
- 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
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 oAuthConnect
method:
private func login(provider: OAuthProvider) {
Task {
do {
let email = try await paraManager.oAuthConnect(provider: provider, webAuthenticationSession: webAuthenticationSession)
handleLogin(email: email)
} catch {
self.error = error
}
}
}
Handling Authentication Result
After a successful OAuth connection, youβll need to handle both new and existing user scenarios:
private func handleLogin(email: String) {
Task {
self.email = email
let userExists = try await paraManager.checkIfUserExists(email: email)
if userExists {
// User exists - complete login with passkey
try await paraManager.login(authorizationController: authorizationController, authInfo: EmailAuthInfo(email: email))
// Navigate to authenticated area of your app
} else {
// New user - create account
try await paraManager.createUser(email: email)
// Navigate to verification or onboarding view
}
}
}
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 verification
case home
}
private func login(provider: OAuthProvider) {
Task {
do {
let email = try await paraManager.oAuthConnect(provider: provider, webAuthenticationSession: webAuthenticationSession)
await handleLogin(email: email)
} catch {
self.error = error
self.showError = true
}
}
}
private func handleLogin(email: String) async {
do {
self.email = email
let userExists = try await paraManager.checkIfUserExists(email: email)
if userExists {
try await paraManager.login(authorizationController: authorizationController, authInfo: EmailAuthInfo(email: email))
navigationState = .home
} else {
try await paraManager.createUser(email: email)
navigationState = .verification
}
} catch {
self.error = error
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 == .verification },
set: { if !$0 { navigationState = .idle } }
)) {
VerifyEmailView(email: email)
}
.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:
- Set up email verification for new users
- Implement secure storage for session management
- Add biometric authentication as an additional security layer