Unity username / password login stops working - "code":206,"error":"Insufficient auth."

Good morning Moralis,

Posting our discord thread on the request of YNikolasKS for help with a bug in the unity SDK we have found. In order to better understand the problem this is our user journey:

We have two applications - Our web front end that we are using for user management, and our Unity game where users can login with only their usernames and passwords.

When we create a user on our web front end with just a username and password, this system works fine. However, when a user binds a wallet to their account via Metamask in the web front end username and password login stops working in Unity. This does not stop username and password working on the web front end. The error that we receive in unity when this problem occurs is:

“Error: HTTP/1.1 400 Bad Request
{“code”:206,“error”:“Insufficient auth.”}.”

It seems like this issue relates to data being set in the authData column in the _User class. Whilst this is blank (it remains blank until a user wallet is bound) password login is possible in Unity. As soon as it is set (when a user binds a wallet in the front end), the above error starts to occur. From our discussion on Discord, it seems like other users are also observing this pattern.

Additionally and strangely, we can see the user login event firing in our logger on the unsuccessful Unity login attempts. We also observe that the session document is updated for the user:

INFO  || 2022-09-15 07:07:28  
Ran cloud function coreservices_track for user undefined with:
Input: {"event":"New server login","userId":"o-216722","distinct_id":"216722","organisation":"XXXX","subdomain":"XXXX"}
Result: {"status":200,"data":{"success":true,"result":true}}

We also observe the _Session document createdWith is updated with user name and password login:

{
  "action": "login",
  "authProvider": "password"
}

Despite this, it does not result in a successfully instantiated Moralis User inside Unity. This leads us to believe this is purely a problem with the Unity SDK.

On discord we saw that other people are experiencing the same problem and the advice from YNikolasKS was to try this:

“For the {“code”:206,“error”:“Insufficient auth.”} issue - There was a security update on the backend that now re-validates the signature every time it is posted. I will need to add a patch for this in the Unity SDK.
For now to get past the issue, before you call user.SaveAsync(), clear the authData array. For example:

user.authData.Clear();
await user.SaveAsync();

The same will work for custom objects”

The only logical place that we could see to try calling these functions was after the unsuccessful login event inside Unity. Our theory being that the user is being partially instantiated and clearing the authData table in the _User document then trying to resave might allow the user to be fully bound. This did not appear to work, though.

If helpful, I have recorded all login events from a cloud logger during this process. Let me know and I will email them to someone.

Additional things I will try today:
Using monogsh to delete the authData column after a wallet has been bound and seeing if this fixes things in Unity without affecting the front end application.

Moralis software versions in use:
Unity:
Unity Moralis SDK release : 1.2.10
Unity version: 2021.3.0f1
Webfront end:
Moralis-v1 : 1.11.0
React-moralis : 1.4.0

1 Like

Here is the full unity stack trace when the error occours.

MoralisSaveException: {“code”:206,“error”:“Insufficient auth.“}
MoralisUnity.Platform.Services.ClientServices.MoralisObjectService.SaveAsync (MoralisUnity.Platform.Objects.MoralisObject item, System.Collections.Generic.IDictionary2[TKey,TValue] operations, System.String sessionToken, System.Threading.CancellationToken cancellationToken) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/Platform/Services/ClientServices/MoralisObjectService.cs:61) Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342)
MoralisUnity.Platform.Objects.MoralisObject.SaveAsync (System.Threading.CancellationToken cancellationToken) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/Platform/Objects/MoralisObject.cs:107)
Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342) MoralisUnity.Platform.Services.ClientServices.MoralisUserService1[TUser].LogInAsync (System.String username, System.String password, MoralisUnity.Platform.Abstractions.IServiceHub1[TUser] serviceHub, System.Threading.CancellationToken cancellationToken) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/Platform/Services/ClientServices/MoralisUserService.cs:69) Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342)
MoralisUnity.Platform.Services.ClientServices.UserServiceExtensions.LogInAsync[TUser] (MoralisUnity.Platform.Abstractions.IServiceHub1[TUser] serviceHub, System.String username, System.String password, System.Threading.CancellationToken cancellationToken) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/Platform/Services/ClientServices/UserServiceExtensions.cs:44) Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342)
MoralisUnity.MoralisClient1[TUser].LogInAsync (System.String username, System.String password, System.Threading.CancellationToken cancellationToken) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/MoralisDynamic.cs:251) Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342)
MoralisUnity.Moralis.LogInAsync (System.String username, System.String password) (at Packages/io.moralis.web3-unity-sdk/Runtime/Core/Moralis.cs:340)
Cysharp.Threading.Tasks.CompilerServices.AsyncUniTask`2[TStateMachine,T].GetResult (System.Int16 token) (at Packages/io.moralis.web3-unity-sdk/Runtime/External/UniTask/Runtime/CompilerServices/StateMachineRunner.cs:342)
Canverse.LoginPopupBh.Connect () (at Assets/UnityElements/Scripts/StateMachine/LoginPopupBh.cs:82)
System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__7_0 (System.Object state) (at <6073cf49ed704e958b8a66d540dea948>:0)
UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at <1332c534a8a44623b2e5cc943a0b790e>:0)
UnityEngine.UnitySynchronizationContext.Exec () (at <1332c534a8a44623b2e5cc943a0b790e>:0)
UnityEngine.UnitySynchronizationContext.ExecuteTasks () (at <1332c534a8a44623b2e5cc943a0b790e>:0)

that solution with

works when the SDK is sending an old authData and it will fail the validation, this happens only for when that authData has a signature specific to a wallet authentication, it will work first time when you login but it will not work later if the same old authData is sent and a solution was to clear that authData, you don’t have to change anything in the database in this case, only the request that is made to the server shouldn’t have that authData set for other requests except for the original login, and that solution was a specific case for when you want to save data in User table after you are already authenticated

you can look at the exact request that is made to the server for when you get that error to see if if is something doesn’t seem ok

1 Like

Thanks for all of the detail it is helpful. I will add this to our internal issues list.

1 Like

@mikeb

Please try this:
Open project in Visual Studio.
Navigate to Moralis.Web3UnitySdk / Runtime / Core / Platform / Services / ClientServices
Open MoralisUserService.cs
Find this code (about line 49)

    public async UniTask<TUser> LogInAsync(string username, string password, IServiceHub<TUser> serviceHub, CancellationToken cancellationToken = default)
    {
        TUser result = default;
        
        string signinData = JsonConvert.SerializeObject(new
        {
            username,
            password,
        });

        Tuple<HttpStatusCode, string> cmdResp =
            await CommandRunner.RunCommandAsync(
                new MoralisCommand($"server/login", method: "POST", data: signinData), cancellationToken: cancellationToken);

        if ((int)cmdResp.Item1 < 300)
        {
            result = JsonSerializer.Deserialize<TUser>(cmdResp.Item2.ToString());

            result.ObjectService = this.ObjectService;
            result.ACL = new MoralisAcl(result);
            await result.SaveAsync();
        }
        else
        {
            Debug.LogError($"LogInAsync failed: {cmdResp.Item2}");
        }

        return result;
    }
  1. Comment out this code (about lines 68 & 69):
    result.ACL = new MoralisAcl(result);
    await result.SaveAsync();
  2. Save and try again.

Where should I paste these codes?

Sorry for the delayed response, we had a few things to get out the way for our testing.
We can confirm the above fix is working well.

Thanks for your help!