NnCredentialKit is a comprehensive Swift package designed to handle user authentication workflows, including email/password sign-up, social login (Apple Sign-In, Google Sign-In), and account linking. This package streamlines the process of managing credentials, reauthentication, and account deletion.
- Account Link Section: Easily integrate account linking for various providers, with customizable colors and accessibility support.
- Credential Management: Load and manage credentials for Apple, Google, and email/password logins.
- Reauthentication Workflow: Handle reauthentication for sensitive actions using custom alerts.
- Social Sign-In Integration: Seamlessly integrate Apple Sign-In and Google Sign-In flows with reusable components.
- Error Handling: Robust error handling for common authentication issues.
To integrate NnCredentialKit into your Xcode project using Swift Package Manager:
-
In Xcode, go to File > Swift Packages > Add Package Dependency.
-
Enter the following repository URL:
https://github.com/nikolainobadi/NnCredentialKit -
Choose the version
3.0.0. -
Select the target where you want to add the package.
If you are using NnCredentialKit in another Swift package, add it to your Package.swift dependencies:
.package(url: "https://github.com/nikolainobadi/NnCredentialKit", from: "3.0.0")Then, in the target you want to use NnCredentialKit, add it to the list of dependencies:
.target(
name: "YourTargetName",
dependencies: [
.product(name: "NnCredentialKit", package: "NnCredentialKit"),
.product(name: "NnCredentialKitAccessibility", package: "NnCredentialKit") // optional for access to accessibility identifiers
]
)Import
NnCredentialKitin your Swift file and implement the required delegates to start managing authentication flows.
GoogleSignInService and AppleSignInService help manage Google and Apple sign-ins.
let appleCredentialInfo = try await AppleSignInService().createAppleTokenInfo()
let googleCredentialInfo = try await GoogleSignInService.signIn(rootVC: viewController)Alternatively, you can use SocialCredentialManager to handle both operations:
let socialManager = SocialCredentialManager(appleSignInScopes: [.email])
let appleCredentialInfo = try await socialManager.loadAppleCredential()
let googleCredentialInfo = try await socialManager.loadGoogleCredential()The top-most UIViewController will be used automatically during Google Sign-In. The method to retrieve it is below:
extension UIApplication {
func getTopViewController() -> UIViewController? {
var topController = connectedScenes
.filter { $0.activationState == .foregroundActive }
.map { $0 as? UIWindowScene }
.compactMap { $0 }
.first?
.windows
.filter { $0.isKeyWindow }
.first?
.rootViewController
// ensures any presented views will be treated as 'top-most' viewController
while let presentedViewController = topController?.presentedViewController {
topController = presentedViewController
}
return topController
}
}The AccountLinkSection view provides a way to display and manage linked accounts within your app. It supports Apple, Google, and email/password providers. It requires an AccountLinkSectionColorsConfig for customizing text colors and an AccountLinkDelegate to perform the credential linking.
import NnCredentialKit
struct ContentView: View {
var body: some View {
AccountLinkSection(
config: .init(providerNameColor: .primary, emailColor: .secondary),
delegate: YourAccountLinkDelegate(),
appleSignInScopes: [.email, .fullName],
preventUnlinkingLastProvider: true
) { delegate in
Button(delegate.buttonText) {
Task {
try? await delegate.linkAction()
}
}
}
}
}By default, preventUnlinkingLastProvider is set to true, which prevents users from unlinking their only authentication method. This ensures users always have at least one way to sign in. When enabled, the link/unlink button is automatically hidden when a provider is the only one linked to the account.
Set preventUnlinkingLastProvider: false to allow users to unlink their last provider (not recommended for most use cases).
When using Firebase Authentication, it's common for operations like updating sensitive user information (email, password, or account linking) to fail if the user’s sign-in session is considered too old. Firebase throws an error with the .requiresRecentLogin code in these cases.
NnCredentialKit is designed to handle this automatically by providing a secure reauthentication flow whenever a .reauthRequired result occurs. After reauthentication is successfully completed, the originally intended operation is automatically retried without any extra logic needed in your code.
This ensures smooth Firebase integration, especially for:
- Linking additional sign-in providers
- Deleting user accounts
- Updating sensitive credentials
When performing Firebase auth operations, you can detect if reauthentication is needed using the following helper:
func handleAuthOperation(_ operation: @escaping () async throws -> Void) async -> AccountCredentialResult {
do {
try await operation()
return .success
} catch let nsError as NSError {
if let authError = AuthErrorCode(rawValue: nsError.code), authError == .requiresRecentLogin {
return .reauthRequired
}
return .failure(nsError)
}
}You can integrate handleAuthOperation inside your AccountLinkDelegate implementation like this:
func linkProvider(with type: CredentialType) async -> AccountCredentialResult {
return await handleAuthOperation {
try await delegate.link(to: type)
}
}
func unlinkProvider(_ type: AuthProviderType) async -> AccountCredentialResult {
return await handleAuthOperation {
try await delegate.unlink(from: type)
}
}In these examples:
delegate.link(to:)anddelegate.unlink(from:)represent your Firebase linking/unlinking methods.handleAuthOperationensures any.requiresRecentLoginFirebase error is automatically escalated to.reauthRequired, allowing NnCredentialKit to seamlessly handle reauthentication.
NnCredentialKit depends on the following external libraries:
- GoogleSignIn (Google Sign-In)
- AuthenticationServices (Apple Sign-In)
Any feedback or ideas to enhance NnCredentialKit would be greatly appreciated.
Please feel free to open an issue or submit a pull request if you'd like to help improve this Swift package.
NnCredentialKit is available under the MIT license. See the LICENSE file for more information.