diff --git a/src/Auth/AuthCredential.cs b/src/Auth/AuthCredential.cs index 79cc9a8..0431c59 100644 --- a/src/Auth/AuthCredential.cs +++ b/src/Auth/AuthCredential.cs @@ -5,6 +5,7 @@ /// public abstract class AuthCredential { + public string TenantId { get; set; } public FirebaseProviderType ProviderType { get; set; } } } diff --git a/src/Auth/FirebaseAuthClient.cs b/src/Auth/FirebaseAuthClient.cs index 0ea5b9d..e89b5cc 100644 --- a/src/Auth/FirebaseAuthClient.cs +++ b/src/Auth/FirebaseAuthClient.cs @@ -81,7 +81,7 @@ public event EventHandler AuthStateChanged } } - public async Task SignInWithRedirectAsync(FirebaseProviderType authType, SignInRedirectDelegate redirectDelegate) + public async Task SignInWithRedirectAsync(FirebaseProviderType authType, SignInRedirectDelegate redirectDelegate, string tenantId = null) { var provider = this.config.GetAuthProvider(authType); @@ -92,15 +92,15 @@ public async Task SignInWithRedirectAsync(FirebaseProviderType a await this.CheckAuthDomain(); - var continuation = await oauthProvider.SignInAsync(); - var redirectUri = await redirectDelegate(continuation.Uri).ConfigureAwait(false); + var continuation = await oauthProvider.SignInAsync(tenantId); + var redirectUri = await redirectDelegate(continuation.Uri).ConfigureAwait(false); if (string.IsNullOrEmpty(redirectUri)) { return null; } - var userCredential = await continuation.ContinueSignInAsync(redirectUri).ConfigureAwait(false); + var userCredential = await continuation.ContinueSignInAsync(redirectUri, tenantId).ConfigureAwait(false); this.SaveToken(userCredential.User); @@ -120,9 +120,9 @@ public async Task SignInWithCredentialAsync(AuthCredential crede return userCredential; } - public async Task SignInAnonymouslyAsync() + public async Task SignInAnonymouslyAsync(string tenantId = null) { - var response = await this.signupNewUser.ExecuteAsync(new SignupNewUserRequest { ReturnSecureToken = true }).ConfigureAwait(false); + var response = await this.signupNewUser.ExecuteAsync(new SignupNewUserRequest { ReturnSecureToken = true, TenantId = tenantId }).ConfigureAwait(false); var credential = new FirebaseCredential { ExpiresIn = response.ExpiresIn, @@ -144,14 +144,15 @@ public async Task SignInAnonymouslyAsync() return new UserCredential(user, null, OperationType.SignIn); } - public async Task FetchSignInMethodsForEmailAsync(string email) + public async Task FetchSignInMethodsForEmailAsync(string email, string tenantId = null) { await this.CheckAuthDomain().ConfigureAwait(false); var request = new CreateAuthUriRequest { ContinueUri = this.config.RedirectUri, - Identifier = email + Identifier = email, + TenantId = tenantId }; var response = await this.createAuthUri.ExecuteAsync(request).ConfigureAwait(false); @@ -159,36 +160,36 @@ public async Task FetchSignInMethodsForEmailAsync(stri return new FetchUserProvidersResult(email, response.Registered, response.SigninMethods, response.AllProviders); } - public async Task SignInWithEmailAndPasswordAsync(string email, string password) + public async Task SignInWithEmailAndPasswordAsync(string email, string password, string tenantId = null) { await this.CheckAuthDomain().ConfigureAwait(false); var provider = (EmailProvider)this.config.GetAuthProvider(FirebaseProviderType.EmailAndPassword); - var result = await provider.SignInUserAsync(email, password).ConfigureAwait(false); + var result = await provider.SignInUserAsync(email, password, tenantId).ConfigureAwait(false); this.SaveToken(result.User); return result; } - public async Task CreateUserWithEmailAndPasswordAsync(string email, string password, string displayName = null) + public async Task CreateUserWithEmailAndPasswordAsync(string email, string password, string displayName = null, string tenantId = null) { await this.CheckAuthDomain().ConfigureAwait(false); var provider = (EmailProvider)this.config.GetAuthProvider(FirebaseProviderType.EmailAndPassword); - var result = await provider.SignUpUserAsync(email, password, displayName).ConfigureAwait(false); + var result = await provider.SignUpUserAsync(email, password, displayName, tenantId).ConfigureAwait(false); this.SaveToken(result.User); return result; } - public async Task ResetEmailPasswordAsync(string email) + public async Task ResetEmailPasswordAsync(string email, string tenantId = null) { await this.CheckAuthDomain().ConfigureAwait(false); var provider = (EmailProvider)this.config.GetAuthProvider(FirebaseProviderType.EmailAndPassword); - await provider.ResetEmailPasswordAsync(email).ConfigureAwait(false); + await provider.ResetEmailPasswordAsync(email, tenantId).ConfigureAwait(false); } public void SignOut() diff --git a/src/Auth/FirebaseAuthException.cs b/src/Auth/FirebaseAuthException.cs index c36ba1f..b25f4fe 100644 --- a/src/Auth/FirebaseAuthException.cs +++ b/src/Auth/FirebaseAuthException.cs @@ -40,15 +40,18 @@ public AuthErrorReason Reason /// public class FirebaseAuthLinkConflictException : FirebaseAuthException { - public FirebaseAuthLinkConflictException(string email, IEnumerable providers) - : base($"An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address: {email}", AuthErrorReason.AccountExistsWithDifferentCredential) + public FirebaseAuthLinkConflictException(string email, IEnumerable providers, string tenantId = null) + : base($"An account already exists{(string.IsNullOrEmpty(tenantId) ? "" : $" in tenant {tenantId}")} with the same email address but different sign-in credentials. Sign in using a provider associated with this email address: {email}", AuthErrorReason.AccountExistsWithDifferentCredential) { - this.Email = email; + this.Email = email; this.Providers = providers; + this.TenantId = tenantId; } public string Email { get; } + public string TenantId { get; set; } + public IEnumerable Providers { get; } } diff --git a/src/Auth/IFirebaseAuthClient.cs b/src/Auth/IFirebaseAuthClient.cs index 765c505..53bd10d 100644 --- a/src/Auth/IFirebaseAuthClient.cs +++ b/src/Auth/IFirebaseAuthClient.cs @@ -22,29 +22,30 @@ public interface IFirebaseAuthClient /// /// Gets a list of sign-in methods for given email. If there are no methods, it means the user with given email doesn't exist. /// - Task FetchSignInMethodsForEmailAsync(string email); + Task FetchSignInMethodsForEmailAsync(string email, string tenantId = null); /// /// Creates a new user with given email, password and display name (optional) and signs this user in. /// - Task CreateUserWithEmailAndPasswordAsync(string email, string password, string displayName = null); + Task CreateUserWithEmailAndPasswordAsync(string email, string password, string displayName = null, string tenantId = null); /// /// Signs in as an anonymous user. /// - Task SignInAnonymouslyAsync(); + Task SignInAnonymouslyAsync(string tenantId = null); /// /// Signs in via third party OAuth providers - e.g. Google, Facebook etc. /// /// Type of the provider, must be an oauth one. /// Delegate which should invoke the passed uri for oauth authentication and return the final redirect uri. - Task SignInWithRedirectAsync(FirebaseProviderType authType, SignInRedirectDelegate redirectDelegate); + /// Optional tenant id.. + Task SignInWithRedirectAsync(FirebaseProviderType authType, SignInRedirectDelegate redirectDelegate, string tenantId = null); /// /// Signs in with email and password. If the email & password combination is incorrect, is thrown. /// - Task SignInWithEmailAndPasswordAsync(string email, string password); + Task SignInWithEmailAndPasswordAsync(string email, string password, string tenantId = null); /// /// Sign in with platform specific credential. For example: @@ -57,11 +58,11 @@ public interface IFirebaseAuthClient /// /// Sends a password reset email to given address. /// - Task ResetEmailPasswordAsync(string email); + Task ResetEmailPasswordAsync(string email, string tenantId = null); /// /// Signs current user out. /// void SignOut(); } -} \ No newline at end of file +} diff --git a/src/Auth/Providers/AppleProvider.cs b/src/Auth/Providers/AppleProvider.cs index 5619a94..ecd3f5f 100644 --- a/src/Auth/Providers/AppleProvider.cs +++ b/src/Auth/Providers/AppleProvider.cs @@ -9,7 +9,7 @@ public AppleProvider() this.AddScopes(DefaultEmailScope); } - public static AuthCredential GetCredential(string accessToken) => GetCredential(FirebaseProviderType.Apple, accessToken, OAuthCredentialTokenType.AccessToken); + public static AuthCredential GetCredential(string accessToken, string tenantId = null) => GetCredential(FirebaseProviderType.Apple, accessToken, tenantId, OAuthCredentialTokenType.AccessToken); public override FirebaseProviderType ProviderType => FirebaseProviderType.Apple; diff --git a/src/Auth/Providers/EmailProvider.cs b/src/Auth/Providers/EmailProvider.cs index fc4fc25..00b0328 100644 --- a/src/Auth/Providers/EmailProvider.cs +++ b/src/Auth/Providers/EmailProvider.cs @@ -27,39 +27,42 @@ internal override void Initialize(FirebaseAuthConfig config) this.linkAccount = new SetAccountLink(config); } - public static AuthCredential GetCredential(string email, string password) + public static AuthCredential GetCredential(string email, string password, string tenantId = null) { return new EmailCredential { ProviderType = FirebaseProviderType.EmailAndPassword, Email = email, - Password = password + Password = password, + TenantId = tenantId }; } - public Task ResetEmailPasswordAsync(string email) + public Task ResetEmailPasswordAsync(string email, string tenantId = null) { var request = new ResetPasswordRequest { - Email = email + Email = email, + TenantId = tenantId }; return this.resetPassword.ExecuteAsync(request); } - public Task SignInUserAsync(string email, string password) + public Task SignInUserAsync(string email, string password, string tenantId = null) { - return this.SignInWithCredentialAsync(GetCredential(email, password)); + return this.SignInWithCredentialAsync(GetCredential(email, password, tenantId)); } - public async Task SignUpUserAsync(string email, string password, string displayName) + public async Task SignUpUserAsync(string email, string password, string displayName, string tenantId = null) { - var authCredential = GetCredential(email, password); + var authCredential = GetCredential(email, password, tenantId); var signupResponse = await this.signupNewUser.ExecuteAsync(new SignupNewUserRequest { Email = email, Password = password, - ReturnSecureToken = true + ReturnSecureToken = true, + TenantId = tenantId }).ConfigureAwait(false); var credential = new FirebaseCredential @@ -105,7 +108,8 @@ protected internal override async Task SignInWithCredentialAsync { Email = ec.Email, Password = ec.Password, - ReturnSecureToken = true + ReturnSecureToken = true, + TenantId = ec.TenantId }).ConfigureAwait(false); var user = await this.GetUserInfoAsync(response.IdToken).ConfigureAwait(false); diff --git a/src/Auth/Providers/FacebookProvider.cs b/src/Auth/Providers/FacebookProvider.cs index 690414f..fe69204 100644 --- a/src/Auth/Providers/FacebookProvider.cs +++ b/src/Auth/Providers/FacebookProvider.cs @@ -9,7 +9,7 @@ public FacebookProvider() this.AddScopes(DefaultEmailScope); } - public static AuthCredential GetCredential(string accessToken) => GetCredential(FirebaseProviderType.Facebook, accessToken, OAuthCredentialTokenType.AccessToken); + public static AuthCredential GetCredential(string accessToken, string tenantId = null) => GetCredential(FirebaseProviderType.Facebook, accessToken, tenantId, OAuthCredentialTokenType.AccessToken); public override FirebaseProviderType ProviderType => FirebaseProviderType.Facebook; diff --git a/src/Auth/Providers/GithubProvider.cs b/src/Auth/Providers/GithubProvider.cs index 0a378a4..77a5eb7 100644 --- a/src/Auth/Providers/GithubProvider.cs +++ b/src/Auth/Providers/GithubProvider.cs @@ -2,7 +2,7 @@ { public class GithubProvider : OAuthProvider { - public static AuthCredential GetCredential(string accessToken) => GetCredential(FirebaseProviderType.Github, accessToken, OAuthCredentialTokenType.AccessToken); + public static AuthCredential GetCredential(string accessToken, string tenantId = null) => GetCredential(FirebaseProviderType.Github, accessToken, tenantId, OAuthCredentialTokenType.AccessToken); public override FirebaseProviderType ProviderType => FirebaseProviderType.Github; } diff --git a/src/Auth/Providers/GoogleProvider.cs b/src/Auth/Providers/GoogleProvider.cs index 8df1e49..afb3915 100644 --- a/src/Auth/Providers/GoogleProvider.cs +++ b/src/Auth/Providers/GoogleProvider.cs @@ -10,7 +10,7 @@ public GoogleProvider() this.AddScopes(DefaultProfileScope, DefaultEmailScope); } - public static AuthCredential GetCredential(string token, OAuthCredentialTokenType tokenType = OAuthCredentialTokenType.AccessToken) => GetCredential(FirebaseProviderType.Google, token, tokenType); + public static AuthCredential GetCredential(string token, OAuthCredentialTokenType tokenType = OAuthCredentialTokenType.AccessToken, string tenantId = null) => GetCredential(FirebaseProviderType.Google, token, tenantId, tokenType); public override FirebaseProviderType ProviderType => FirebaseProviderType.Google; diff --git a/src/Auth/Providers/MicrosoftProvider.cs b/src/Auth/Providers/MicrosoftProvider.cs index f16987a..21c772d 100644 --- a/src/Auth/Providers/MicrosoftProvider.cs +++ b/src/Auth/Providers/MicrosoftProvider.cs @@ -15,7 +15,7 @@ public MicrosoftProvider() this.AddScopes(DefaultScopes); } - public static AuthCredential GetCredential(string accessToken) => GetCredential(FirebaseProviderType.Microsoft, accessToken, OAuthCredentialTokenType.AccessToken); + public static AuthCredential GetCredential(string accessToken, string tenantId = null) => GetCredential(FirebaseProviderType.Microsoft, accessToken, tenantId, OAuthCredentialTokenType.AccessToken); public override FirebaseProviderType ProviderType => FirebaseProviderType.Microsoft; } diff --git a/src/Auth/Providers/OAuthContinuation.cs b/src/Auth/Providers/OAuthContinuation.cs index dc2b833..3490bfb 100644 --- a/src/Auth/Providers/OAuthContinuation.cs +++ b/src/Auth/Providers/OAuthContinuation.cs @@ -33,8 +33,9 @@ internal OAuthContinuation(FirebaseAuthConfig config, string uri, string session /// /// Final uri that user lands on after completing sign in in browser. /// Optional id token of an existing Firebase user. If set, it will effectivelly perform account linking. + /// Optional tenant id. /// - public async Task ContinueSignInAsync(string redirectUri, string idToken = null) + public async Task ContinueSignInAsync(string redirectUri, string idToken = null, string tenantId = null) { var (user, response) = await this.verifyAssertion.ExecuteAndParseAsync( this.providerType, @@ -44,11 +45,12 @@ public async Task ContinueSignInAsync(string redirectUri, string RequestUri = redirectUri, SessionId = this.sessionId, ReturnIdpCredential = true, - ReturnSecureToken = true + ReturnSecureToken = true, + TenantId = tenantId }).ConfigureAwait(false); var provider = this.config.GetAuthProvider(this.providerType) as OAuthProvider ?? throw new InvalidOperationException($"{this.providerType} is not a OAuthProvider"); - var credential = provider.GetCredential(response); + var credential = provider.GetCredential(response, tenantId); response.Validate(credential); diff --git a/src/Auth/Providers/OAuthProvider.cs b/src/Auth/Providers/OAuthProvider.cs index 6e8fea3..1cd64e3 100644 --- a/src/Auth/Providers/OAuthProvider.cs +++ b/src/Auth/Providers/OAuthProvider.cs @@ -20,13 +20,14 @@ public OAuthProvider() protected virtual string LocaleParameterName => null; - protected static AuthCredential GetCredential(FirebaseProviderType providerType, string accessToken, OAuthCredentialTokenType tokenType) + protected static AuthCredential GetCredential(FirebaseProviderType providerType, string accessToken, string tenantId, OAuthCredentialTokenType tokenType) { return new OAuthCredential { ProviderType = providerType, Token = accessToken, - TokenType = tokenType + TokenType = tokenType, + TenantId = tenantId }; } @@ -50,15 +51,16 @@ public virtual FirebaseAuthProvider AddCustomParameters(params KeyValuePair SignInAsync() + internal virtual async Task SignInAsync(string tenantId = null) { if (this.LocaleParameterName != null && !this.parameters.ContainsKey(this.LocaleParameterName)) { @@ -71,6 +73,7 @@ internal virtual async Task SignInAsync() ProviderId = this.ProviderType, CustomParameters = this.parameters, OauthScope = this.GetParsedOauthScopes(), + TenantId = tenantId }; var response = await this.createAuthUri.ExecuteAsync(request).ConfigureAwait(false); @@ -87,10 +90,11 @@ protected internal override async Task SignInWithCredentialAsync PostBody = c.GetPostBodyValue(credential.ProviderType), PendingToken = c.GetPendingTokenValue(), ReturnIdpCredential = true, - ReturnSecureToken = true + ReturnSecureToken = true, + TenantId = credential.TenantId }).ConfigureAwait(false); - credential = this.GetCredential(response); + credential = this.GetCredential(response, credential.TenantId); response.Validate(credential); @@ -107,14 +111,15 @@ protected internal override async Task LinkWithCredentialAsync(s PostBody = c.GetPostBodyValue(c.ProviderType), PendingToken = c.GetPendingTokenValue(), ReturnIdpCredential = true, - ReturnSecureToken = true + ReturnSecureToken = true, + TenantId = credential.TenantId }).ConfigureAwait(false); - credential = this.GetCredential(response); + credential = this.GetCredential(response, credential.TenantId); response.Validate(credential); - return new UserCredential(user, this.GetCredential(response), OperationType.Link); + return new UserCredential(user, credential, OperationType.Link); } protected string GetParsedOauthScopes() diff --git a/src/Auth/Providers/TwitterProvider.cs b/src/Auth/Providers/TwitterProvider.cs index 623d1eb..5c118a0 100644 --- a/src/Auth/Providers/TwitterProvider.cs +++ b/src/Auth/Providers/TwitterProvider.cs @@ -4,13 +4,14 @@ namespace Firebase.Auth.Providers { public class TwitterProvider : OAuthProvider { - public static AuthCredential GetCredential(string token, string secret) + public static AuthCredential GetCredential(string token, string secret, string tenantId) { return new TwitterCredential { ProviderType = FirebaseProviderType.Twitter, Token = token, - Secret = secret + Secret = secret, + TenantId = tenantId }; } @@ -18,9 +19,9 @@ public static AuthCredential GetCredential(string token, string secret) protected override string LocaleParameterName => "lang"; - internal override AuthCredential GetCredential(VerifyAssertionResponse response) + internal override AuthCredential GetCredential(VerifyAssertionResponse response, string tenantId) { - return GetCredential(response.OauthAccessToken, response.OauthTokenSecret); + return GetCredential(response.OauthAccessToken, response.OauthTokenSecret, tenantId); } internal class TwitterCredential : OAuthCredential diff --git a/src/Auth/Requests/CreateAuthUri.cs b/src/Auth/Requests/CreateAuthUri.cs index b78bd9d..3f826e8 100644 --- a/src/Auth/Requests/CreateAuthUri.cs +++ b/src/Auth/Requests/CreateAuthUri.cs @@ -32,6 +32,8 @@ public class CreateAuthUriRequest public string OauthScope { get; set; } public string Identifier { get; set; } + + public string TenantId { get; set; } } /// diff --git a/src/Auth/Requests/ResetPassword.cs b/src/Auth/Requests/ResetPassword.cs index 6a6afef..a799616 100644 --- a/src/Auth/Requests/ResetPassword.cs +++ b/src/Auth/Requests/ResetPassword.cs @@ -12,6 +12,8 @@ public ResetPasswordRequest() public string Email { get; set; } public string RequestType { get; set; } + + public string TenantId { get; set; } } public class ResetPasswordResponse diff --git a/src/Auth/Requests/SignupNewUser.cs b/src/Auth/Requests/SignupNewUser.cs index cef6eb6..63f66e4 100644 --- a/src/Auth/Requests/SignupNewUser.cs +++ b/src/Auth/Requests/SignupNewUser.cs @@ -6,7 +6,8 @@ public class SignupNewUserRequest public string Password { get; set; } - public bool ReturnSecureToken { get; set; } + public bool ReturnSecureToken { get; set; } + public string TenantId { get; set; } } public class SignupNewUserResponse diff --git a/src/Auth/Requests/VerifyAssertion.cs b/src/Auth/Requests/VerifyAssertion.cs index dc510be..b7aa8c0 100644 --- a/src/Auth/Requests/VerifyAssertion.cs +++ b/src/Auth/Requests/VerifyAssertion.cs @@ -7,52 +7,53 @@ namespace Firebase.Auth.Requests public class VerifyAssertionRequest : IdTokenRequest { public string RequestUri { get; set; } - + public string PostBody { get; set; } - + public string PendingToken { get; set; } public string SessionId { get; set; } public bool ReturnIdpCredential { get; set; } - public bool ReturnSecureToken { get; set; } + public bool ReturnSecureToken { get; set; } + public string TenantId { get; set; } } public class VerifyAssertionResponse { public string FederatedId { get; set; } - + public FirebaseProviderType ProviderId { get; set; } - + public string Email { get; set; } - + public bool EmailVerified { get; set; } - + public string FirstName { get; set; } - + public string FullName { get; set; } - + public string LastName { get; set; } - + public string PhotoUrl { get; set; } - + public string LocalId { get; set; } - + public string DisplayName { get; set; } - + public string IdToken { get; set; } - + public string Context { get; set; } - + public string OauthAccessToken { get; set; } - + public string OauthTokenSecret { get; set; } - + public int OauthExpireIn { get; set; } - + public string RefreshToken { get; set; } - + public int ExpiresIn { get; set; } public string OauthIdToken { get; set; } @@ -77,14 +78,15 @@ public class VerifyAssertion : FirebaseRequestBase