I'm interacting with a REST service and when I get a 401 error I call AccountManager.invalidateAuthToken with my account type and the token I'm trying to invalidate, but nothing happens. I call getAuthToken right after invalidateAuthToken and I just get back the invalid token.
Related
The token generated by the ADAL is having an expiry of 1 hour. To create the token the app is calling the ADAL method acquireToken. When reopening the app or engaging with the app which was in background/idle for more than 1 hour, the token has to be refreshed. This refresh should happen in the background without user consent. For this, the app is calling the ADAL method acquireTokenSilentSync. This function is throwing an exception an ADAL exception AuthenticationException. Due to this, the app has to be force-closed so that the token will be created again once reopening. Logs are below
Token cache item contains empty refresh token, cannot continue refresh token request ver:3.0.2 Android 28 null
Microsoft.ADAL.request_id: 34533-b84f-45ae-a4f5-29e7h6789d02
Microsoft.ADAL.api_error_code: AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED
Microsoft.ADAL.is_frt: false
Microsoft.ADAL.device_id: lSZf/vWb4AcUTIgbKXDVlQ7jYmBGmLPEMLwHYQao3C4=
Microsoft.ADAL.cache_event_count: 3
[2020-05-14 05:11:21 - 344267-f177-48f8-ad39-ec085udh240c] AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED:Prompt is not allowed and failed to get token. No result returned from acquireTokenSilent ver:3.0.2 Android 28 null
The acquireTokenSilentSync function will first look at the cache and automatically checks for the token expiration. Additionally, if no suitable access token is found in the cache, but refresh token is available, the function will use the refresh token automatically. This method will not show UI for the user. If prompt is needed, the method will return an exception. The Error prompt you are receiving says the Token cache is empty, make sure token is available in the Cache
My app uses Firebase to authenticate users by phone number, a migration from Digits.
I add the idToken from Firebase to my calls.
I listen with an interceptor on my httpclient if a 401 was trown, if so, I logged out.
I noticed after one hour the 401 came in, so I added an addIdTokenListener in my App class. When it changes I update my token to sign my calls.
It worked, but not flawless, sometimes a 401 was thrown and I still logged the user out...
I am writing something in my interceptor to get the IdToken from the user, but the call firebaseUser.getIdToken() is async. So I'm starting to make things complicated, I guess.
Could anyone point me in the right direction? What is your workflow?
You're going in the right direction. One thing you may want to do is alter your logic a little based on the reason for the ID token validation failure. You can unpack the ID token data yourself and check the expiration field. If the token has expired, return a different code that triggers the retrieval process, before trying the call again.
I´m trying to use FCM to send Firebase Notifications, but I have a Application using one Firebase Project and a library using another Firebase Project. I want to receive the token from library Firebase Project to receive Firebase Notifications.
When I try directly receive the token using:
FirebaseInstanceId.getInstance().getToken();
I received a valid token, but from Application Firebase Project. If i try to force in getInstance() the library Firebase Project, using:
FirebaseInstanceId.getInstance(FirebaseApp.getInstance("ABC")).getToken();
I receive null. If I try to use Application or Library Firebase Project passing parameters in getToken() as:
FirebaseInstanceId.getInstance().getToken(getApplication().getResources().getString(R.string.gcm_defaultSenderId), FirebaseMessaging.INSTANCE_ID_SCOPE);
or
FirebaseInstanceId.getInstance(FirebaseApp.getInstance("ABC")).getToken(getApplication().getResources().getString(R.string.gcm_defaultSenderId), FirebaseMessaging.INSTANCE_ID_SCOPE);
I received the same valid token from Application Firebase Project.
the R.string.gcm_defaultSenderId is from library project resources
There is another way to receive Library Firebase Project token or I'm doing something wrong?
This is my understanding of what you are observing based on my experiments and the documentation.
When you first call getToken() using a FirebaseApp other then the default, there is no token and communication with the server is required to produce one. A null value is returned and the process to fetch a token is initiated. The documentation for getToken() says it returns "the master token or null if the token is not yet available". After a few seconds the token is received. You can detect that event using the onTokenRefresh() method of FirebaseInstanceIdService, if you have implemented that. On subsequent calls to getToken() for the non-default app, the token will be present and returned immediately by getToken().
I think the calls to get a scoped token always return a token because they are blocking (see docs), and wait for the interaction with the server to complete before returning a result.
I made a mistake in FirebaseApp.initializeApp(), because I forgot to set:
.setGcmSenderId(getApplication().getResources().getString(R.string.gcm_defaultSenderId))
in FirebaseOptions.Builder().
After that change, I receive a valid Library Firebase Token in getToken() and in onTokenRefresh()
I'm using GCM on Android.
I use InstanceID.getInstance(...).getToken(...) to receive a push token, but in some cases (after application updates or re-install) I receive an invalid token.
When the server returns a NotRegistered error, I've connected with a debugger and called InstanceID.getInstance(...).getToken(...). But this token is not valid (I've tried to send push via curl -s "https://android.googleapis.com/gcm/send" ... using this token), I receive NotRegistered error.
Why instanceID could return invalid token?
It shouldn't give invalid token.
Have you applied all procedures?
InstanceIDListenerService: When the token changes via the app
updates, etc.
RegistrationIntentService: When the token changes, you receive it via InstanceIDListenerService and call this intent to get a new
token.
Finally, I found a solution.
I worked with instanceID from two different threads. I called getToken(...) two times simultaneously. If instance doesn't have a cache, it get token from network. I think, it sends two requests in my case and there is no guarantee of it's order. So instanceID cached one token, but google cloud another one.
Should I be invalidating and requesting a new token every time I need to make a request using a Google auth token from the AccountManager or is there an 'expired-at' time stamp I can use to see if it is still valid.
There is no expiry time provided in the HTTP response from the Google service, so I think you need to ensure that if the auth-token fails to provide access, you use that as the trigger to get a new auth token. Or you could acquire a new token each time the application starts, or create your own timeout.
http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
Looking at the HTTP response, the status code is 302 (it's redirecting you to provide auth token) and the "Set-Cookie" field in the header is not present. You could key off that.
if (res.getStatusLine().getStatusCode() == 302 && res.getHeaders("Set-Cookie").length == 0) {
// we need a new token
// invalidate account manager logic here
}
Failing to get that cookie from Google seems to signify it's time to grab a new token from AccountManager.
As there is no accepted answer yet:
I do it by firing my requests in a try block, then catching any exceptions and check if it's a 401 with if (e.getMessage().equals("401 Unauthorized")) { ... }.
Then, invalidate the auth token, request a new one and retry the request.
You need to call invalidateAuthToken(String, String) when you know the token has expired. i.e. when the request fails with an authentication error.