CallDeferred is definitely the way to go. This is the Thread Safe API call for executing methods in Godot. Although the examples are with gdscript it is applicable in C# as well, but you can read more about it here: Thread-safe APIs — Godot Engine (stable) documentation in English
In case you want a different thread to be running and you managing it, you could just go the ordinary C# way about it by creating a Thread/Task.
And some context on what is happening here:
When a player wants to login, we send an async call to Login with some params and we also give it a callback method (OnLogin) to be executed when the login has finished. The client connects to the game server and sends some info about itself to the server. When the server recieves the info about the player, verifies it and if valid then runs the game world scene for the player and adds it for other players as well.
Something nice i figured out of just experimenting is that when you use the Callable.From() to call such methods you can pass whatever you want, it does not have to be Godot Variant.
I have further experimented with this pattern and there is one thing you should keep in mind when using this approach - the method that you call with Callable.From() should return void or Variant, so it only does work because the method is async void. AFAIK this would not be an issue in a godot project, but making async methods return void instead of Task is something that is advised NOT being done in C# ^^.