@@ -25,8 +25,8 @@ public class FirebaseAuthProvider : IDisposable, IFirebaseAuthProvider
2525 private const string GoogleSetAccountUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}" ;
2626 private const string GoogleCreateAuthUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/createAuthUri?key={0}" ;
2727 private const string GoogleUpdateUserPassword = "https://identitytoolkit.googleapis.com/v1/accounts:update?key={0}" ;
28-
29-
28+
29+
3030 private const string ProfileDeleteDisplayName = "DISPLAY_NAME" ;
3131 private const string ProfileDeletePhotoUrl = "PHOTO_URL" ;
3232
@@ -55,7 +55,7 @@ public async Task<FirebaseAuthLink> SignInWithCustomTokenAsync(string customToke
5555 firebaseAuthLink . User = await this . GetUserAsync ( firebaseAuthLink . FirebaseToken ) . ConfigureAwait ( false ) ;
5656 return firebaseAuthLink ;
5757 }
58-
58+
5959 /// <summary>
6060 /// Using the idToken of an authenticated user, get the details of the user's account
6161 /// </summary>
@@ -66,14 +66,14 @@ public async Task<User> GetUserAsync(string firebaseToken)
6666 var content = $ "{{\" idToken\" :\" { firebaseToken } \" }}";
6767 var responseData = "N/A" ;
6868 try
69- {
69+ {
7070 var response = await this . client . PostAsync ( new Uri ( string . Format ( GoogleGetUser , this . authConfig . ApiKey ) ) , new StringContent ( content , Encoding . UTF8 , "application/json" ) ) . ConfigureAwait ( false ) ;
7171 responseData = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
7272 response . EnsureSuccessStatusCode ( ) ;
7373
7474 var resultJson = JObject . Parse ( responseData ) ;
7575 var user = JsonConvert . DeserializeObject < User > ( resultJson [ "users" ] . First ( ) . ToString ( ) ) ;
76- return user ;
76+ return user ;
7777 }
7878 catch ( Exception ex )
7979 {
@@ -92,15 +92,26 @@ public async Task<User> GetUserAsync(FirebaseAuth auth)
9292 }
9393
9494 /// <summary>
95- /// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.
95+ /// Using the provided access token from third party auth provider (google, facebook...), or ID token (apple), get the firebase auth with token and basic user credentials.
9696 /// </summary>
9797 /// <param name="authType"> The auth type. </param>
98- /// <param name="oauthAccessToken "> The access token retrieved from login provider of your choice. </param>
98+ /// <param name="oauthToken "> The access token or ID token retrieved from login provider of your choice. </param>
9999 /// <returns> The <see cref="FirebaseAuth"/>. </returns>
100- public async Task < FirebaseAuthLink > SignInWithOAuthAsync ( FirebaseAuthType authType , string oauthAccessToken )
100+ public async Task < FirebaseAuthLink > SignInWithOAuthAsync ( FirebaseAuthType authType , string oauthToken )
101101 {
102102 var providerId = this . GetProviderId ( authType ) ;
103- var content = $ "{{\" postBody\" :\" access_token={ oauthAccessToken } &providerId={ providerId } \" ,\" requestUri\" :\" http://localhost\" ,\" returnSecureToken\" :true}}";
103+
104+ string content ;
105+
106+ switch ( authType )
107+ {
108+ case FirebaseAuthType . Apple :
109+ content = $ "{{\" postBody\" :\" id_token={ oauthToken } &providerId={ providerId } \" ,\" requestUri\" :\" http://localhost\" ,\" returnSecureToken\" :true}}";
110+ break ;
111+ default :
112+ content = $ "{{\" postBody\" :\" access_token={ oauthToken } &providerId={ providerId } \" ,\" requestUri\" :\" http://localhost\" ,\" returnSecureToken\" :true}}";
113+ break ;
114+ }
104115
105116 FirebaseAuthLink firebaseAuthLink = await this . ExecuteWithPostContentAsync ( GoogleIdentityUrl , content ) . ConfigureAwait ( false ) ;
106117 firebaseAuthLink . User = await this . GetUserAsync ( firebaseAuthLink . FirebaseToken ) . ConfigureAwait ( false ) ;
@@ -174,7 +185,7 @@ public async Task<FirebaseAuthLink> SignInWithEmailAndPasswordAsync(string email
174185 firebaseAuthLink . User = await this . GetUserAsync ( firebaseAuthLink . FirebaseToken ) . ConfigureAwait ( false ) ;
175186 return firebaseAuthLink ;
176187 }
177-
188+
178189 /// <summary>
179190 /// Change a password from an user with his token.
180191 /// </summary>
@@ -187,8 +198,8 @@ public async Task<FirebaseAuthLink> ChangeUserPassword(string idToken, string pa
187198
188199 return await this . ExecuteWithPostContentAsync ( GoogleUpdateUserPassword , content ) . ConfigureAwait ( false ) ;
189200 }
190-
191-
201+
202+
192203 /// <summary>
193204 /// Creates new user with given credentials.
194205 /// </summary>
@@ -273,15 +284,15 @@ public async Task DeleteUserAsync(string firebaseToken)
273284 {
274285 var content = $ "{{ \" idToken\" : \" { firebaseToken } \" }}";
275286 var responseData = "N/A" ;
276-
277- try
287+
288+ try
278289 {
279290 var response = await this . client . PostAsync ( new Uri ( string . Format ( GoogleDeleteUserUrl , this . authConfig . ApiKey ) ) , new StringContent ( content , Encoding . UTF8 , "application/json" ) ) . ConfigureAwait ( false ) ;
280291 responseData = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
281-
292+
282293 response . EnsureSuccessStatusCode ( ) ;
283294 }
284- catch ( Exception ex )
295+ catch ( Exception ex )
285296 {
286297 AuthErrorReason errorReason = GetFailureReason ( responseData ) ;
287298 throw new FirebaseAuthException ( GoogleDeleteUserUrl , content , responseData , ex , errorReason ) ;
@@ -296,12 +307,12 @@ public async Task SendPasswordResetEmailAsync(string email)
296307 {
297308 var content = $ "{{\" requestType\" :\" PASSWORD_RESET\" ,\" email\" :\" { email } \" }}";
298309 var responseData = "N/A" ;
299-
310+
300311 try
301312 {
302313 var response = await this . client . PostAsync ( new Uri ( string . Format ( GoogleGetConfirmationCodeUrl , this . authConfig . ApiKey ) ) , new StringContent ( content , Encoding . UTF8 , "application/json" ) ) . ConfigureAwait ( false ) ;
303314 responseData = await response . Content . ReadAsStringAsync ( ) . ConfigureAwait ( false ) ;
304-
315+
305316 response . EnsureSuccessStatusCode ( ) ;
306317 }
307318 catch ( Exception ex )
@@ -550,6 +561,9 @@ private static AuthErrorReason GetFailureReason(string responseData)
550561 case "A system error has occurred - missing or invalid postBody" :
551562 failureReason = AuthErrorReason . SystemError ;
552563 break ;
564+ case "MISSING_OR_INVALID_NONCE : Duplicate credential received. Please try again with a new credential." :
565+ failureReason = AuthErrorReason . DuplicateCredentialUse ;
566+ break ;
553567
554568 //possible errors from Email/Password Account Signup (via signupNewUser or setAccountInfo) or Signin
555569 case "INVALID_EMAIL" :
@@ -563,7 +577,7 @@ private static AuthErrorReason GetFailureReason(string responseData)
563577 case "EMAIL_EXISTS" :
564578 failureReason = AuthErrorReason . EmailExists ;
565579 break ;
566-
580+
567581 //possible errors from Account Delete
568582 case "USER_NOT_FOUND" :
569583 failureReason = AuthErrorReason . UserNotFound ;
@@ -610,12 +624,14 @@ private static AuthErrorReason GetFailureReason(string responseData)
610624 break ;
611625 }
612626
613- if ( failureReason == AuthErrorReason . Undefined )
614- {
627+ if ( failureReason == AuthErrorReason . Undefined )
628+ {
615629 //possible errors from Email/Password Account Signup (via signupNewUser or setAccountInfo)
616- if ( errorData ? . error ? . message ? . StartsWith ( "WEAK_PASSWORD :" ) ?? false ) failureReason = AuthErrorReason . WeakPassword ;
630+ if ( errorData ? . error ? . message ? . StartsWith ( "WEAK_PASSWORD :" ) ?? false ) failureReason = AuthErrorReason . WeakPassword ;
617631 //possible errors from Email/Password Signin
618632 else if ( errorData ? . error ? . message ? . StartsWith ( "TOO_MANY_ATTEMPTS_TRY_LATER :" ) ?? false ) failureReason = AuthErrorReason . TooManyAttemptsTryLater ;
633+ //ID Token issued is stale to sign-in (e.g. with Apple)
634+ else if ( errorData ? . error ? . message ? . StartsWith ( "ERROR_INVALID_CREDENTIAL" ) ?? false ) failureReason = AuthErrorReason . StaleIDToken ;
619635 }
620636 }
621637 }
@@ -638,6 +654,7 @@ private string GetProviderId(FirebaseAuthType authType)
638654 {
639655 case FirebaseAuthType . Facebook :
640656 case FirebaseAuthType . Google :
657+ case FirebaseAuthType . Apple :
641658 case FirebaseAuthType . Github :
642659 case FirebaseAuthType . Twitter :
643660 return authType . ToEnumString ( ) ;
0 commit comments