AuthStateProvider's current behaviour is that it only publishes sessionToken, kSync and kXCS values if it finds the account in the "Married" state. Unfortunately, this isn't quite correct. Cohabiting state has all of the necessary bits of information, and we could easily find the account in that state.
In Fennec, as far as I can tell, there are two main reasons we can find ourselves in a Cohabiting state:
- certificate is stale
- we have bad credentials
Both of these scenarios may happen:
- as we're obtaining a token from the token server using a BrowserID assertion - this happens during every sync. Or...
- as we're obtaining a scoped auth token using a BrowserID assertion - I can't recall if we actually use this code; I don't think we do. This is part of Android's AbstractAccountAuthenticator.
In both cases, BrowserID assertion is generated as part of the Married state, and it relies on a valid certificate, which is generated while we're in the Cohabitating state.
Maximum value for the certificate duration is 24hrs, according to https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#request-body-27.
We request for a certificate to last 12hrs:
However, we do not obtain a certificate every time we need to generate an assertion. We "cache" the certificate as part of data bound to the state.
Once we get to the Married state (meaning that we were able to obtain a valid certificate, with good credentials around good), we stay in it - certificate is now part of the persisted state data. Next time we sync maybe after our certificate has expired, in which case we'll transition into a Cohabiting state:
At that point, if the AuthStateProvider is queried, it'll find the (perfectly fine) account in a Cohabiting state, and currently will refuse to provide credentials.
If another sync is performed, we will obtain a fresh certificate in the Cohabiting state, transition into Married state, succeed in obtaining a token from the token server, and then sync using that token.
If the AuthStateProvider is queried again then, it'll see the account is in Married state.
So in essence, the current behaviour of AuthStateProvider works fine if the browser is frequently used. In that scenario, stale certificates are regenerated as needed as part of regular syncing. This is why we didn't uncover this bug during initial testing, and this is subtle enough to slip in the review.
Another angle here is that a 401 from the token server may, in theory, also mean that we have bad credentials - not just a stale certificate. In practice, I don't believe that to be the case, but need to confirm.
It also doesn't matter very much - clients of AuthStateProvider will quickly learn that the credentials they've obtained are no longer any good, and they're expected to handle this scenario gracefully.