Offline Support for Anonymous Authentication

Hello,

I've just updated Remote Config to 3.1.3 (from 2.1.2) which ultimately requires that I start to use Unity Authentication.

I was already using UnityServices.InitializeAsync (for the new Analytics) so it was fairly easy to implement.

So I updated to Authentication 2.0.0 and using AuthenticationService.Instance.SignInAnonymouslyAsync() noticed the following...

  1. Device Online
  2. Open Game
  3. UnityServices.InitializeAsync() -> Success
  4. AuthenticationService.Instance.SignInAnonymouslyAsync() -> (IsSignedIn = True, PlayerId = XYZ, AccessToken = XYZ, SessionTokenExists = True)
  5. Exit Game

  6. Device Offline

  7. Open Game

  8. UnityServices.InitializeAsync() -> Success

  9. AuthenticationService.Instance.SignInAnonymouslyAsync() -> (IsSignedIn = False, Player Id = XYZ, AccessToken = , SessionTokenExists = True)

Firstly, why is Anonymous Authentication not signing in when offline? The credentials appear to be cached (in PlayerPrefs) and the Player Id & Session Token are persisting, although the Access Token is not (what is the difference!?)

Secondly SignInAnonymouslyAsync is throwing numerous errors when offline (stalling the player) which is not ideal.

Because Authentication is not signing in, it's also backing up other sub-systems (i.e. Remote Config) as that requires a sign-in. Surely Remote Config could just sign-in using cached credentials and then report cached\default values? Although maybe that's a question for the RC forum.

Something doesn't feel right here. I would expect consistent behaviour even when offline (if cached)

Any help would be much appreciated.

8235561--1076520--AnonymousAuthenticationOfflineErrors.png

2 Likes

Is anyone from Unity able to comment on this please?

I updated to 2.1.1 today and it exhibits the same behaviour.

Hi @PeachyPixels ,

I'll investigate this for you and get right back to you once I have some more information

Thank you for your patience

1 Like

Thanks @Julian-Unity3D

If there's anything you need me to try in the meantime, please just ask away and I'll do what I can.

Hey PeachyPixels,

The auth team wouldn't expect stalling to occur in this instance, can you share more info on the error messages you're receiving?

In terms of the difference between Session Token and Access Token:
* Session Token is a convenience that allows the SDK to log back in without having to do the full auth flow. An authenticated user can only have one valid session token for a quick relog at a time. If the session token is missing, or is outdated (Say the user signed in on a different device) then they'll need to go through the full authentication flow to get logged in.

  • Access Token is something that gets passed in with actual requests to the various services, and if the user hasn't yet logged in (i.e. they're offline and so the session token can't be used to log the user back in) then we wouldn't expect it to be present.

Cheers!

1 Like

[quote=“unity_Ctri”, post:5, topic: 886132]
The auth team wouldn’t expect stalling to occur in this instance, can you share more info on the error messages you’re receiving?
[/quote]Hey @unity_Ctri

If calling SignInAnonymouslyAsync when offline, numerous warnings and errors are thrown. This unfortunately pauses the player, made worse by the retry mechanism I have in-place above and beyond Unity’s.

Wrapping the call in exception handling or even using ContinueWith (as I am doing) still ‘stalls’ the player due to the errors shown in the above screenshot. Even in device builds, the end result is a log file that is flooded with warnings & error messages.

With regards to ‘stalling’ other sub-systems. Remote config now requires authentication, so if sign-in doesn’t occur (offline) then remote config won’t call the settings updated event, so cached or default values are never set (obviously remote won’t be in that scenario)

All in all, not very developer friendly.

I guess the main issues are…

  1. Offline anonymous authentication doesn’t appear to work
  2. The raising of authentication errors (and ‘stalling’ the player)
  3. Remote config (haven’t tested other sub-systems yet) not working if not authenticated

Hopefully that all makes sense :slight_smile:

1 Like

Hello,
We cannot support 'offline' authentication or fake sign-in.

Signing in provides us an access token which allows other services to make operations.
Other services that require a valid access token to make requests would fail causing more problems.

Awaiting the auth task should not 'block' your player, can you elaborate on that?
When offline, this should fail almost instantly.

I would also recommend to not retry the auth operation since we already retry internally as you have noticed

Remote Config is a feature that should work without authentication - and the cache should work when offline.
Remote Config only uses the player id from authentication when available for overrides/segmentation.
I'm curious about your use case and how remote config call fails when offline

[quote=“erickb_unity”, post:7, topic: 886132]
Remote Config is a feature that should work without authentication - and the cache should work when offline.
Remote Config only uses the player id from authentication when available for overrides/segmentation.
I’m curious about your use case and how remote config call fails when offline
[/quote]Hi @erickb_unity

Thanks for the detailed reply, it’s much appreciated.

Ok, there’s a lot to answer here so let me send them as individual messages.

The below is using…

Unity 2020.3.36f1
Authentication 2.1.1
Remote Config 3.1.3

Firstly, Remote Config - I’ve been experimenting this morning and am seeing some inconsistent results.

The following is using Remote Config with no Authentication Sign-In.

  1. Device Offline
  2. Start Game
  3. UnityServices.InitializeAsync(…)
  4. AuthenticationService.Instance.SignOut(true) → Testing Purposes Only

This is what usually happens…

  1. RemoteConfigService.Instance.FetchConfigs(…) → Results in below
    a) Auth Service not initialized warning logged
    b) FetchCompleted event is fired (either defaults or cache reported)

But occasionally does this…

  1. RemoteConfigService.Instance.FetchConfigs(…) → Results in below
    a) Core Service not initialized warning logged
    b) Auth Service not initialized warning logged
    c) FetchCompleted event is not fired (so not even default or cached values applied)

So this is why I thought Remote Config wasn’t calling FetchCompleted. The first time I ran it, it followed scenario 5a/b/c hence I thought Remote Config required sign-in to work.

But I can’t work out why it’s doing this. It looks like the Unity (Core) Services initialisation is unpredictable when offline. Sometimes it appears to initialise and sometimes not. When it doesn’t (and the Core Service not initialized warning is logged) then Remote Config doesn’t work at all.

I’m initialising using ContinueWith() but I see the same issue with just plain exception handling…

await UnityServices.InitializeAsync(GetInitialisationOptions()).ContinueWith((task) => ProcessInitialiseServices(task));

It’s odd and probably doesn’t help you much, but it’s really difficult to pin down the reason for the inconsistent behaviour.

Update: Just spotted something...

When offline and initialising the core services (UnityServices.InitializeAsync) the length of time it takes to initialise varies from almost instantaneously to 15 seconds.

If it takes too long, my game init code continues onto the next sub-system and when it comes to Remote Config the core services haven't been initialised, so it doesn't fire the event. That results in the scenario above.

But what to-do when Unity is being so unpredictable? If a game requires sub-system B that requires sub-system A and that doesn't work consistently, it's making life a lot harder.

The above scenario is only using the easiest scenario of offline from the get go. Factor in variable connectivity at various points of a game's lifetime and it's even more complicated.

It's a broad comment I know, but it feels like the new UGS do not handle offline as robustly as they should. I hit issues with initialising the new Analytics when offline and had to code defensively around it. It's not helped by the fact that each and every UGS seems to handle these situations\concerns differently. Some handle it better than others. Some with exceptions, some with callbacks etc. There is little consistency across the API's.

Unity primarily targets mobile platforms\devices where coverage can be very spotty and at worse, entirely non-existent. So it feels like the new UGS should have offline support as a primary concern\feature.

Anyway, hopefully this is taken constructively and does help improve things in the long run :-)

[quote=“erickb_unity”, post:7, topic: 886132]
I would also recommend to not retry the auth operation since we already retry internally as you have noticed
[/quote]Hi @erickb_unity

The reason for auto retry (on my part) was that Authentication only appears to retry across a very short time period, less than a second (see attached image)

If the device subsequently comes online (seconds\minutes later) it doesn’t appear to sign-in (even using the the SignedIn event)

For example…

  1. Device Offline
  2. Start Game
  3. AuthenticationService.Instance.SignInAnonymouslyAsync() → (Unity retries a few times in less than a second then stops)
  4. Game Init Continues After Waiting N Seconds.
  5. Device Online
  6. Authentication does not sign-in and will stay permanently signed out.

So unless the device is online at the point the game is started, it will never sign-in. Even if the player has signed in previously and credentials are cached.

Hence why I implemented an auto retry coroutinue. Of course I could be missing something entirely here, it wouldn’t be the first time :slight_smile: So please correct me if I’m wrong.

8244114--1078338--AuthenticationSignInWhenOffline.png

Hello, there's a lot to investigate here.

UnityServices.InitializeAsync taking 15 seconds is really not normal.
Can you let us know all the services packages that you are using beyond Remote Config & Authentication, and also how you are calling InitializeAsync exactly?

Also your auto-retry for auth at longer intervals for your offline scenario makes sense!

RemoteConfig is a special service that will work even prior to Unity Services initialization for backwards compatibility reasons, but will log these warnings about services not being initialized.

We will look to improve the logs in the future as we want to avoid warnings for what could be intended behavior.

2 Likes

Hi @erickb_unity

Thanks for the reply again. Yes I did throw a lot at you there, sorry :)

With a clearer mind today though, you can probably condense it down to the following...

1. UnityServices.InitializeAsync(...) - Should it initialise offline?

It appears to most of the time, but sometimes doesn't. This is what was stopping Remote Config from not firing the update event. Maybe not for your team though.

2. AuthenticationService.Instance.SignInAnonymouslyAsync(...) - Does it auto retry?

After looking through the code, I think the answer is no, but feel it should. Given the unpredictability of coverage on mobile devices, the UGS services should be able to cope with this.

At the very least I feel all the UGS services should all auto-retry and\or rely on cached data\credentials more. So once a UGS service is initialised (either online or from cached data) that's it from a game's point of view. Internally though that would be different and they would have to handle offline situations differently.

It vastly simplifies devs working with the services and means we can focus on the game rather than the services.

I believe one of your other teams is working on an auto-retry for one of the other services at present (can't remember which, sorry). It would be great if there was a consistent approach to this across the board.

3. AuthenticationService.Instance.SignInAnonymouslyAsync(...) - Should it support offline?

It would definitely make life easier for devs if it did. Especially as the service is already geared towards cached credentials. It seems odd having a cached player id (and other data) yet offline support is not offered.

Of course requirements for other 'online' services (i.e. Steam, Google etc) may well be different. I'm only referring to anonymous here.

4. What is pausing\stalling the player?

When the Auth service fails to initialise (for example, when offline) it pauses the player, which is far from ideal.

Is it the logged error doing this or exceptions? Because even handled exceptions pause the player. Not a deal breaker, but it does make debugging issues like this in the player far harder. Especially time sensitive ones.

As for the Unity services that I'm utilising...

Unity Advertisement (4.2.1)
Unity Analytics (4.0.1)
Unity Authentication (2.1.1)
Unity Purchasing (4.2.1)
Unity Remote Config (3.1.3)

As always, happy to help out where possible so just say if there's anything further you need.

Btw... I've switched to using the Auth sign-in events and dropped the ContinueWith pattern. I did that for consistency with the approach I took for Analytics, given that that service offers no success\fail events.

But the Auth service does, so thought it better to utilise them. An auto-retry would fit those events perfectly, so if you ever take that approach with Auth I suspect there would be no interface changes required.

Apologies, one more I forgot to include...

5. AuthenticationService.Instance.SignInAnonymouslyAsync(...) - Stack trace logged if exception thrown (even if handled)

Which can be frustrating as it makes the logs harder to read, made worse if an auto-retry mechanism is implemented.

I was not able to reproduce the long initialization/stalling locally with the list of packages you have. My setup might be a bit different.

As for the logs, we will evaluate removing them from operations that are handled by developers. We agree that it's not ideal.

For the retry policy, we are still evaluating different possibilities. Every developer has different needs so it is hard to come up with a standard solution that will fit everyone. Nothing stops you from creating your own at the moment based on your needs.

Thanks for all the feedback!

1 Like

[quote=“erickb_unity”, post:15, topic: 886132]
As for the logs, we will evaluate removing them from operations that are handled by developers. We agree that it’s not ideal.
[/quote]Great, thanks.

[quote=“erickb_unity”, post:15, topic: 886132]
For the retry policy, we are still evaluating different possibilities. Every developer has different needs so it is hard to come up with a standard solution that will fit everyone. Nothing stops you from creating your own at the moment based on your needs.
[/quote]My games main init routine attempts to initialise each sub-system in order.

If a sub-system initialises (within N seconds) then main init moves to the next sub-system.

If a sub-system fails to initialise (within N seconds) it will wait (until N seconds has passed) and keep retrying (every N seconds) whilst main init moves to the next sub-system.

If a sub-system fails to initialise (after N seconds) it will wait until it does fail then wait (another N seconds) and keep retrying (every N seconds) whilst main init moves to the next sub-system.

If sub-system B requires sub-system A then an extra (initialised) check is required as part of that sub-systems initialisation process.

Hopefully that all makes sense :slight_smile:

Basically, sub-systems retry in the background, none are critical to gameplay and at most they will only retry every N seconds. I’ve used this approach across all Unity Services with several games now and it appears to work well (assuming Unity services handle mid-game connectivity losses)

So ultimately if all the Unity services could handle this as transparently as possible, it would make it far easier for devs to work with Unity services.

At the very least, a service configurable wait time (N seconds) would be needed. Icing on the cake would be an InitialiseRetry event\callback, so developers have an idea of when a retry occurs.

Or even better, a UGS init daemon that would handle all this logic in a centralised manner.

Hope that helps and thanks again for the feedback.

Any updates on this? I have similar issue. Remote config is working fine on editor (online & offline) with or without the authentication code , but not when I build on device, it freaks out and has a lot of errors.

If I add the authentication segment then is working on iOS when the app has Internet but freaks out if the device is in offline mode, I need to be able to boot the app and get a cached remote config in offline mode.

Remote Config 3.3.1

private async void InitializeUnityServices()
{
    if (UnityServices.State == ServicesInitializationState.Uninitialized)
    {
        await UnityServices.InitializeAsync();
    }

    if (!AuthenticationService.Instance.IsSignedIn)
    {
        await AuthenticationService.Instance.SignInAnonymouslyAsync();
    }   

    SetEnvironment();
    FetchConfig();
}

Any updates? I have the same issue where

  • await UnityServices.InitializeAsync();

Completely blocks the app from starting on ios (works fine in editor and android) when the app is started without internet on the device.