Skip to content

Instantly share code, notes, and snippets.

@shaps80
Created January 29, 2025 20:42
Show Gist options
  • Save shaps80/f2656351fb61e5318a9ddaa6797184c8 to your computer and use it in GitHub Desktop.
Save shaps80/f2656351fb61e5318a9ddaa6797184c8 to your computer and use it in GitHub Desktop.
Simplifies sign-in with  integration by providing an Environment-driven action similar to `openWindow` and others.
import SwiftUI
import AuthenticationServices
public struct SignInWithAppleAction: Sendable {
public func callAsFunction() async throws -> ASAuthorization {
try await Coordinator().perform()
}
}
public extension EnvironmentValues {
/// Sign in with Apple using modern concurrency and Swift error handling
@Entry var signInWithApple: SignInWithAppleAction = .init()
}
private extension SignInWithAppleAction {
final class Coordinator: NSObject, ASAuthorizationControllerDelegate, Sendable {
private var continuation: CheckedContinuation<ASAuthorization, Error>?
func perform() async throws -> ASAuthorization {
try await withCheckedThrowingContinuation { continuation in
let provider = ASAuthorizationAppleIDProvider()
let request = provider.createRequest()
request.requestedScopes = [.email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
DispatchQueue.global(qos: .utility).async {
controller.performRequests()
}
self.continuation = continuation
}
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
continuation?.resume(returning: authorization)
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: any Error) {
continuation?.resume(throwing: error)
}
}
}
extension ASAuthorizationController: @retroactive @unchecked Sendable {}
@shaps80
Copy link
Author

shaps80 commented Jan 29, 2025

Example

@Environment(\.signInWithApple) private var signIn

var body: some View {
    Button("Sign in with Apple") {
        Task {
            do {
                let auth = try await signIn()
                print(auth)
            } catch {
                print(error)
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment