@@ -226,31 +226,46 @@ class UserViewController: UIViewController, DataSourceProviderDelegate {
226
226
227
227
// MARK: - Sign in with Apple Token Revocation Flow
228
228
229
- // For Sign in with Apple
230
- private var currentNonce : String ?
229
+ /// Used for Sign in with Apple token revocation flow.
230
+ private var continuation : CheckedContinuation < ASAuthorizationAppleIDCredential , Error > ?
231
231
232
- // [START token_revocation_deleteuser]
233
232
private func deleteCurrentUser( ) {
234
- do {
235
- let nonce = try CryptoUtils . randomNonceString ( )
236
- currentNonce = nonce
237
- let appleIDProvider = ASAuthorizationAppleIDProvider ( )
238
- let request = appleIDProvider. createRequest ( )
239
- request. requestedScopes = [ . fullName, . email]
240
- request. nonce = CryptoUtils . sha256 ( nonce)
241
-
242
- let authorizationController = ASAuthorizationController ( authorizationRequests: [ request] )
243
- authorizationController. delegate = self
244
- authorizationController. presentationContextProvider = self
245
- authorizationController. performRequests ( )
246
- } catch {
247
- // In the unlikely case that nonce generation fails, show error view.
248
- displayError ( error)
233
+ Task {
234
+ guard let user else { return }
235
+ do {
236
+ let needsTokenRevocation = user. providerData
237
+ . contains { $0. providerID == AuthProviderID . apple. rawValue }
238
+ if needsTokenRevocation {
239
+ let appleIDCredential = try await signInWithApple ( )
240
+
241
+ guard let appleIDToken = appleIDCredential. identityToken else {
242
+ print ( " Unable to fetch identify token. " )
243
+ return
244
+ }
245
+ guard let idTokenString = String ( data: appleIDToken, encoding: . utf8) else {
246
+ print ( " Unable to serialise token string from data: \( appleIDToken. debugDescription) " )
247
+ return
248
+ }
249
+
250
+ let nonce = try CryptoUtils . randomNonceString ( )
251
+ let credential = OAuthProvider . credential ( providerID: . apple,
252
+ idToken: idTokenString,
253
+ rawNonce: nonce)
254
+
255
+ try await user. reauthenticate ( with: credential)
256
+ if
257
+ let authorizationCode = appleIDCredential. authorizationCode,
258
+ let authCodeString = String ( data: authorizationCode, encoding: . utf8) {
259
+ try await Auth . auth ( ) . revokeToken ( withAuthorizationCode: authCodeString)
260
+ }
261
+ }
262
+ try await user. delete ( )
263
+ } catch {
264
+ displayError ( error)
265
+ }
249
266
}
250
267
}
251
268
252
- // [END token_revocation_deleteuser]
253
-
254
269
// MARK: - Private Helpers
255
270
256
271
private func getVerificationCode( ) async throws -> String {
@@ -343,48 +358,31 @@ extension UserViewController: ASAuthorizationControllerDelegate,
343
358
ASAuthorizationControllerPresentationContextProviding {
344
359
// MARK: ASAuthorizationControllerDelegate
345
360
346
- // [START token_revocation]
347
- func authorizationController( controller: ASAuthorizationController ,
348
- didCompleteWithAuthorization authorization: ASAuthorization ) {
349
- guard let appleIDCredential = authorization. credential as? ASAuthorizationAppleIDCredential
350
- else {
351
- print ( " Unable to retrieve AppleIDCredential " )
352
- return
353
- }
354
-
355
- guard let _ = currentNonce else {
356
- fatalError ( " Invalid state: A login callback was received, but no login request was sent. " )
357
- }
358
-
359
- guard let appleAuthCode = appleIDCredential. authorizationCode else {
360
- print ( " Unable to fetch authorization code " )
361
- return
362
- }
361
+ func signInWithApple( ) async throws -> ASAuthorizationAppleIDCredential {
362
+ return try await withCheckedThrowingContinuation { continuation in
363
+ self . continuation = continuation
364
+ let appleIDProvider = ASAuthorizationAppleIDProvider ( )
365
+ let request = appleIDProvider. createRequest ( )
366
+ request. requestedScopes = [ . fullName, . email]
363
367
364
- guard let authCodeString = String ( data : appleAuthCode , encoding : . utf8 ) else {
365
- print ( " Unable to serialize auth code string from data: \( appleAuthCode . debugDescription ) " )
366
- return
368
+ let authorizationController = ASAuthorizationController ( authorizationRequests : [ request ] )
369
+ authorizationController . delegate = self
370
+ authorizationController . performRequests ( )
367
371
}
372
+ }
368
373
369
- Task {
370
- do {
371
- try await AppManager . shared. auth ( ) . revokeToken ( withAuthorizationCode: authCodeString)
372
- try await user? . delete ( )
373
- self . updateUI ( )
374
- } catch {
375
- self . displayError ( error)
376
- }
374
+ func authorizationController( controller: ASAuthorizationController ,
375
+ didCompleteWithAuthorization authorization: ASAuthorization ) {
376
+ if case let appleIDCredential as ASAuthorizationAppleIDCredential = authorization. credential {
377
+ continuation? . resume ( returning: appleIDCredential)
378
+ } else {
379
+ fatalError ( " Unexpected authorization credential type. " )
377
380
}
378
381
}
379
382
380
- // [END token_revocation]
381
-
382
383
func authorizationController( controller: ASAuthorizationController ,
383
- didCompleteWithError error: any Error ) {
384
- // Ensure that you have:
385
- // - enabled `Sign in with Apple` on the Firebase console
386
- // - added the `Sign in with Apple` capability for this project
387
- print ( " Sign in with Apple failed: \( error) " )
384
+ didCompleteWithError error: Error ) {
385
+ continuation? . resume ( throwing: error)
388
386
}
389
387
390
388
// MARK: ASAuthorizationControllerPresentationContextProviding
0 commit comments