-
Notifications
You must be signed in to change notification settings - Fork 490
Expand file tree
/
Copy pathFacebookProviderAuthUI.swift
More file actions
132 lines (120 loc) · 4.15 KB
/
FacebookProviderAuthUI.swift
File metadata and controls
132 lines (120 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import AppTrackingTransparency
import FacebookCore
import FacebookLogin
import FirebaseAuth
import FirebaseAuthSwiftUI
import SwiftUI
public class FacebookProviderSwift: AuthProviderSwift {
let scopes: [String]
let providerId = "facebook.com"
private let loginManager = LoginManager()
private var rawNonce: String?
private var shaNonce: String?
// Needed for reauthentication
var isLimitedLogin: Bool = true
public init(scopes: [String] = ["email", "public_profile"], isLimitedLogin: Bool = true) {
self.scopes = scopes
self.isLimitedLogin = isLimitedLogin
}
@MainActor public func createAuthCredential() async throws -> AuthCredential {
let loginType: LoginTracking = isLimitedLogin ? .limited : .enabled
guard let configuration: LoginConfiguration = {
if loginType == .limited {
rawNonce = CommonUtils.randomNonce()
shaNonce = CommonUtils.sha256Hash(of: rawNonce!)
return LoginConfiguration(
permissions: scopes,
tracking: loginType,
nonce: shaNonce!
)
} else {
return LoginConfiguration(
permissions: scopes,
tracking: loginType
)
}
}() else {
throw AuthServiceError
.providerAuthenticationFailed("Failed to create Facebook login configuration")
}
let result = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<
Void,
Error
>) in
loginManager.logIn(
configuration: configuration
) { result in
switch result {
case .cancelled:
continuation
.resume(throwing: AuthServiceError
.signInCancelled("User cancelled sign-in for Facebook"))
case let .failed(error):
continuation.resume(throwing: error)
case .success:
continuation.resume()
}
}
}
if isLimitedLogin {
return try limitedLogin()
} else {
return try classicLogin()
}
}
private func classicLogin() throws -> AuthCredential {
if let token = AccessToken.current,
!token.isExpired {
let credential = FacebookAuthProvider
.credential(withAccessToken: token.tokenString)
return credential
} else {
throw AuthServiceError
.providerAuthenticationFailed(
"Access token has expired or not available. Please sign-in with Facebook before attempting to create a Facebook provider credential"
)
}
}
private func limitedLogin() throws -> AuthCredential {
if let idToken = AuthenticationToken.current {
guard let nonce = rawNonce else {
throw AuthServiceError
.providerAuthenticationFailed(
"`rawNonce` has not been generated for Facebook limited login"
)
}
let credential = OAuthProvider.credential(withProviderID: providerId,
idToken: idToken.tokenString,
rawNonce: nonce)
return credential
} else {
throw AuthServiceError
.providerAuthenticationFailed(
"Authentication is not available. Please sign-in with Facebook before attempting to create a Facebook provider credential"
)
}
}
}
public class FacebookProviderAuthUI: AuthProviderUI {
public var provider: AuthProviderSwift
public let id: String = "facebook.com"
public init(provider: AuthProviderSwift) {
self.provider = provider
}
@MainActor public func authButton() -> AnyView {
AnyView(SignInWithFacebookButton(facebookProvider: provider as! FacebookProviderSwift))
}
}