OAuth 2.0 authentication library for iOS and macOS with PKCE support and customizable SwiftUI sign-in UI.
- iOS 18+ / macOS 15+
- Swift 6.2+
- Xcode 16+
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/nicktrienenern/RxAuthSwift.git", from: "1.0.0"),
]Then add the targets you need:
.target(
name: "YourApp",
dependencies: [
"RxAuthSwift", // Core OAuth logic
"RxAuthSwiftUI", // Sign-in UI components (optional)
]
)import RxAuthSwift
let config = RxAuthConfiguration(
issuer: "https://auth.example.com",
clientID: "your-client-id",
redirectURI: "yourapp://callback",
scopes: ["openid", "profile", "email"]
)Endpoint paths default to /api/oauth/authorize, /api/oauth/token, /api/oauth/userinfo but can be overridden:
let config = RxAuthConfiguration(
issuer: "https://auth.example.com",
clientID: "your-client-id",
redirectURI: "yourapp://callback",
authorizePath: "/oauth/authorize",
tokenPath: "/oauth/token",
userInfoPath: "/oauth/me"
)let authManager = OAuthManager(configuration: config)You can inject custom token storage:
let authManager = OAuthManager(
configuration: config,
tokenStorage: MyCustomTokenStorage()
)@main
struct MyApp: App {
@State private var authManager = OAuthManager(configuration: config)
var body: some Scene {
WindowGroup {
ContentView()
.task {
await authManager.checkExistingAuth()
}
}
}
}Simple (with appearance customization):
import RxAuthSwiftUI
RxSignInView(
manager: authManager,
appearance: RxSignInAppearance(
icon: .image(Image("MyLogo")),
title: "Welcome",
subtitle: "Sign in to continue",
signInButtonTitle: "Get Started",
accentColor: .purple,
secondaryColor: .pink
)
)With callbacks:
RxSignInView(
manager: authManager,
onAuthSuccess: {
// Navigate to home, fetch user data, etc.
},
onAuthFailed: { error in
// Log error, show custom alert, etc.
}
)Advanced (fully custom header with ViewBuilder):
RxSignInView(
manager: authManager,
onAuthSuccess: { print("Signed in!") },
onAuthFailed: { error in print("Failed: \(error)") }
) {
VStack {
Image("Logo")
.resizable()
.frame(width: 100, height: 100)
Text("My App")
.font(.largeTitle.bold())
}
}switch authManager.authState {
case .unknown:
ProgressView()
case .unauthenticated:
RxSignInView(manager: authManager)
case .authenticated:
HomeView(user: authManager.currentUser)
}await authManager.logout()NotificationCenter.default.addObserver(
forName: .rxAuthSessionExpired,
object: nil,
queue: .main
) { _ in
// Handle session expiry
}The SignInIcon enum supports:
.systemImage("lock.shield.fill") // SF Symbol
.image(Image("MyLogo")) // SwiftUI Image
.assetImage("AppIcon", Bundle.main) // Asset catalog
.none // No iconImplement TokenStorageProtocol for custom storage backends:
public protocol TokenStorageProtocol: Sendable {
func saveAccessToken(_ token: String) throws
func getAccessToken() -> String?
func deleteAccessToken() throws
func saveRefreshToken(_ token: String) throws
func getRefreshToken() -> String?
func deleteRefreshToken() throws
func saveExpiresAt(_ date: Date) throws
func getExpiresAt() -> Date?
func isTokenExpired() -> Bool
func clearAll() throws
}UI components automatically use .glassEffect on iOS 26+ / macOS 26+ and fall back to .ultraThinMaterial / .borderedProminent on older platforms.
# macOS
bash scripts/build-macos.sh
# iOS
bash scripts/build-ios.shMIT