Firebase iOS not receiving events after re-auth with JWT - ios

I'm using the Firebase iOS SDK and part of my app experience is group chat. I have a class for each group chat and store a reference to the firebase object as follows:
self.firebaseMessages = [[Firebase alloc] initWithUrl:[NSString stringWithFormat:#"%#/Message/%#", FIREBASE_URL, chat.objectId]];
I then observe each event I'm interested in. This works very well. I use custom auth with JWTs and my issue is when the token expires or the user logs out / in and I re-authenticate. At that point, the callbacks stop firing for the events I'm observing unless I completely restart my app. I know the re-auth was successful because I get a success callback and authdata in the AuthEventWithBlock. When I set values, the database updates and other clients receive those updates. It's just the client that re-auth'd that no longer receives updates.
I've dumbed down my security rules to eliminate that as a possibility:
"Message": {
"$message": {
".read": "auth != null",
".write": "auth != null"
}
}
I re-auth on the root URL:
Firebase *ref = [[Firebase alloc] initWithUrl:FIREBASE_URL];
[ref authWithCustomToken:responseObject[#"auth_token"] withCompletionBlock:^(NSError *error, FAuthData *authData) {
I've tried re-auth on each message URL as well. Also tried re-instantiating all of my Firebase objects.
Also note that I am using [ref unauth] on the root to log the user out and to simulate a token expiration.
What am I missing?

Kato's comment is the solution. Make sure to re-establish event listeners if you lose authentication and re-auth.
Also worth nothing that all of the data will also flow back in when the listeners are re-established. If you're on a screen that streams data from those listeners - like a group chat, you will likely receive data that is already being displayed. Easy enough to handle, though.

Related

Firebase Realtime Database Security Rules ( Read And Write )

Ok I have a Realtime database connected to a app and till today the rules ( read and write ) were set to true , everything was working fine ....but every time a message pops up saying
Your security rules are defined as public, so anyone can steal, modify, or delete data in your database
I tried few things but data was not accessed...data was only accessible when the rules were set to true
but is there any way to modify the rules to make it more secure
I want this Data to be accessed by only few known apps ( My Apps )
Start here in the docs and work your way through. It's very practical and easy to understand.
data was only accessible when the rules were set to true
Firebase RTDB has a public URL, so anyone can try connecting to it. It is your job to decide whether they can do this or not. If your rules for any path/node look like this, it is available to anyone who makes a request:
{
".read": true,
".write": true
}
If you only want to allow users of your app to connect to RTDB, you can use Firebase Auth and use conditions like this:
{
".read": "auth != null"
".write": "auth != null"
}
I want this Data to be accessed by only few known apps ( My Apps )
Access is determined on a user level, not by app. Start here in the docs.
but is there any way to modify the rules to make it more secure
Either in the Firebase Console, or deploy them via the CLI. If you're new to this, start with the Firebase Console and use the Rules Playground to test different rules. See docs for more information.
So unless someone has access to my Google account or a app /web integrated with my database... No one can access the data even if the rules are set to true, am I right ?
Your database is not "integrated". It is a deployed instance that is reachable via a public URL - that's how your clients connect to RTDB. If your rules allow any read or write operation, then your database is wide and open for everyone. Hence, the email that you have received informing you that this is not secure.
{
"rules": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
Currently accepted Rule docs

How to validate fields server side during user creation with Firebase Auth?

I'm trying to use Firebase Auth to create a new user, but I want to validate some fields (pattern matching) using Firestore Security Rules before creating a new account. How can I do that?
In the completion handler for the createUser(withEmail: , password:) function, I am performing some writes to Firestore on successful account creation.
I am facing a problem where sometimes the writes to Firestore may not be successful due to Firestore Secuity Rules (Pattern matching). In this case the write fails but the new user account is still created (since writes are being attempted in completion handler).
// Create User Method - Firebase Auth & Swift
Auth.auth().createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (result, error) in
if error != nil {
print(error?.localizedDescription)
} else {
let userName = [
userName:self.userNameTextField.text!
]
// Writing field Data to Firestore
Firestore.firestore().collection("users").document(self.userNameTextField.text!).setData(userName) {(err) in
if err != nil {
// Rather than throwing a fatalError, how can I ensure new account creation is cancelled so that feedback can be given on the issue with entered field data?
fatalError()
}
I want to ensure a user account is not created in case writes to Firestore are unsuccessful due to a conflict with Firestore Security Rules.
Firebase Authentication doesn't have any security rules. There's currently no way to check if incoming account properties are valid before a user gets created. Security rules only apply to data read and written directly to Cloud Firestore (or Realtime Database, or Cloud Storage) from a mobile or web client.
The only thing you could do is use a Cloud Functions auth trigger to check the account properties after it was created, then delete or deactivate the account if something is wrong.

Do I need to refresh the access token when using Microsoft Graph and How to do it?

I'm using Microsoft Graph SDK for my iOS Application.
Do I need to manually refresh the access token when it expired?
The access token I'm talking about is:
NXOAuth2AccountStore.sharedStore().accounts[0].accessToken
I have tested that I can still query even the accessToken expired. At the time I first logged in, the expired time is 3600 secs. So, I waited 2 hours, test to get user info, events again and still can get it.
I have dump "accessToken.hasExpired" and "accessToken.expiresAt" to make sure access token is expired
Thanks
* More Details *
I follow the sample here:
https://github.com/microsoftgraph/ios-swift-connect-sample
I cannot find any documents about refresh access token on Microsoft Graph:
https://graph.microsoft.io/en-us/code-samples-and-sdks
Yes, you need to refresh tokens periodically when using Graph in your application. More detailed documentation is available through Azure AD's site: https://learn.microsoft.com/en-us/azure/active-directory/active-directory-authentication-scenarios
The suggested auth library you are using contains a method for refreshing this token:
#implementation NXOAuth2AuthenticatorRefreshCallback
If I haven't answered your question, could you be more specific about what you are trying to accomplish? Are you able to use an expired token or are you unable to refresh your old one?
Use this code whenever you need to refresh the access token.
This will act as a patch to predefined code provided in graph sdk and you can extract the token from the method :
+(id)tokenWithResponseBody:(NSString *)theResponseBody tokenType:(NSString *)tokenType;
[MSGraphClient setAuthenticationProvider:AppDel.authentication.authProvider];
_graphClient = [MSGraphClient client];
NSMutableURLRequest * sampleReq = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://graph.microsoft.com/v1.0/me"]];
[_graphClient.authenticationProvider appendAuthenticationHeaders:sampleReq completion:^(NSMutableURLRequest *request, NSError *error){
if(error == nil)
{
}
else
{
[self showToast:#"" message:#"Failure in refresh 0365 token"];
}
}];

Is there a way to detect revoked permissions through Google APIs?

We're trying to find a way to detect revoked permissions through Google APIs without continuously polling the provider to get status updates. Does Google have any sort of notification system for this (a webhook, etc)?
The most recent post I found regarding this was over 2 years ago.
Look here and search for Check For Permissions
Android Permissions
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}

How to force Google OAuth popup in Firebase when user already authenticated previously?

Whenever a user has previously authenticated with Google, it automatically defaults to logging them in with THAT account on subsequent attempts. I want to eliminate this and force the popup/redirect so that a user with multiple google accounts can choose which one to use. How?
Background:
The automatic logging in feature is proving problematic for me as I have a whitelisted set of e-mails for users allowed to use my app. If a Google user chooses the wrong account when first logging in, they can't go back and choose the one associated to their whitelisted e-mail.
Just as #nvnagr said, you can do this with the following code:
var provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
'prompt': 'select_account'
});
But I think you need to update the firebase version to 3.6.0 something.
Google supports a parameter in authentication url to deal with this issue.
If you add prompt=select_account in your request to Google authentication, it'll force the user to do an account selection. See the details and other values of prompt.
https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
I'm not sure if there is an easy way to add this parameter through firebase api.
When you're calling the oAuth function, you can pass a third options parameter to make the authentication last for the session only. This should solve your problem. Docs
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithOAuthPopup("google", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
}, {
remember: 'sessionOnly'
});

Resources