Skip to content

Commit

Permalink
[Auth] Fix delete action in sample app (#13554)
Browse files Browse the repository at this point in the history
  • Loading branch information
ncooke3 authored Aug 30, 2024
1 parent 76fcc90 commit 486a0a0
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 58 deletions.
2 changes: 1 addition & 1 deletion FirebaseAuth/Sources/Swift/User/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ extension User: NSSecureCoding {}
}

/// Renews the user's authentication tokens by validating a fresh set of credentials supplied
/// by the user and returns additional identity provider data.
/// by the user and returns additional identity provider data.
///
/// If the user associated with the supplied credential is different from the current user,
/// or if the validation of the supplied credentials fails; an error is returned and the current
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ class AuthMenuData: DataSourceProvidable {
customAuthDomainSection, appSection, oobSection, multifactorSection]

static var authLinkSections: [Section] {
let allItems = AuthMenuData.sections.flatMap { $0.items }
let allItems = [providerSection, emailPasswordSection, otherSection].flatMap { $0.items }
let header = "Manage linking between providers"
let footer =
"Select an unchecked row to link the currently signed in user to that auth provider. To unlink the user from a linked provider, select its corresponding row marked with a checkmark."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ extension AccountLinkingViewController: ASAuthorizationControllerDelegate,
return
}

let credential = OAuthProvider.credential(withProviderID: "apple.com",
let credential = OAuthProvider.credential(providerID: .apple,
idToken: idTokenString,
rawNonce: nonce)
// Once we have created the above `credential`, we can link accounts to it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,31 +226,46 @@ class UserViewController: UIViewController, DataSourceProviderDelegate {

// MARK: - Sign in with Apple Token Revocation Flow

// For Sign in with Apple
private var currentNonce: String?
/// Used for Sign in with Apple token revocation flow.
private var continuation: CheckedContinuation<ASAuthorizationAppleIDCredential, Error>?

// [START token_revocation_deleteuser]
private func deleteCurrentUser() {
do {
let nonce = try CryptoUtils.randomNonceString()
currentNonce = nonce
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
request.nonce = CryptoUtils.sha256(nonce)

let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = self
authorizationController.performRequests()
} catch {
// In the unlikely case that nonce generation fails, show error view.
displayError(error)
Task {
guard let user else { return }
do {
let needsTokenRevocation = user.providerData
.contains { $0.providerID == AuthProviderID.apple.rawValue }
if needsTokenRevocation {
let appleIDCredential = try await signInWithApple()

guard let appleIDToken = appleIDCredential.identityToken else {
print("Unable to fetch identify token.")
return
}
guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
print("Unable to serialise token string from data: \(appleIDToken.debugDescription)")
return
}

let nonce = try CryptoUtils.randomNonceString()
let credential = OAuthProvider.credential(providerID: .apple,
idToken: idTokenString,
rawNonce: nonce)

try await user.reauthenticate(with: credential)
if
let authorizationCode = appleIDCredential.authorizationCode,
let authCodeString = String(data: authorizationCode, encoding: .utf8) {
try await Auth.auth().revokeToken(withAuthorizationCode: authCodeString)
}
}
try await user.delete()
} catch {
displayError(error)
}
}
}

// [END token_revocation_deleteuser]

// MARK: - Private Helpers

private func getVerificationCode() async throws -> String {
Expand Down Expand Up @@ -343,48 +358,31 @@ extension UserViewController: ASAuthorizationControllerDelegate,
ASAuthorizationControllerPresentationContextProviding {
// MARK: ASAuthorizationControllerDelegate

// [START token_revocation]
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization) {
guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential
else {
print("Unable to retrieve AppleIDCredential")
return
}

guard let _ = currentNonce else {
fatalError("Invalid state: A login callback was received, but no login request was sent.")
}

guard let appleAuthCode = appleIDCredential.authorizationCode else {
print("Unable to fetch authorization code")
return
}
func signInWithApple() async throws -> ASAuthorizationAppleIDCredential {
return try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]

guard let authCodeString = String(data: appleAuthCode, encoding: .utf8) else {
print("Unable to serialize auth code string from data: \(appleAuthCode.debugDescription)")
return
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.performRequests()
}
}

Task {
do {
try await AppManager.shared.auth().revokeToken(withAuthorizationCode: authCodeString)
try await user?.delete()
self.updateUI()
} catch {
self.displayError(error)
}
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization) {
if case let appleIDCredential as ASAuthorizationAppleIDCredential = authorization.credential {
continuation?.resume(returning: appleIDCredential)
} else {
fatalError("Unexpected authorization credential type.")
}
}

// [END token_revocation]

func authorizationController(controller: ASAuthorizationController,
didCompleteWithError error: any Error) {
// Ensure that you have:
// - enabled `Sign in with Apple` on the Firebase console
// - added the `Sign in with Apple` capability for this project
print("Sign in with Apple failed: \(error)")
didCompleteWithError error: Error) {
continuation?.resume(throwing: error)
}

// MARK: ASAuthorizationControllerPresentationContextProviding
Expand Down

0 comments on commit 486a0a0

Please sign in to comment.