It would be awesome if SpatialOS offered this feature built-in. You would think that player authentication would be a common use-case. Every MMO I have ever played uses it.
Offering a first class auth integration isn’t on our roadmap. You’re correct that every MMO needs authentication, but so far we’ve only been asked for integrations like Steam and Playfab: as third party providers they offer a fantastic suite of tools for managing distribution, metrics and refunds etc.
Is there a specific use case you’re thinking of in terms of distribution or auth?
Somehow I missed this topic … but to add:
I have integrated Playfab as an authentication provider (and planning on using more of its features to be able to link another app to my game). I used the following workflow:
- I added the Playfab SDK
- I split the Bootstrap script into a Client and Worker Bootstrap
- In the Client bootstrap I do not automatically connect to Spatial upon starting
- Instead I first authenticate with Playfab (currently using the device identifier so I don’t need to create a user management front yet)
- As soon as the event triggers that indicates that login has succeeded I
5.1. Populate the Spatial metadata with the Playfab PlayerId (this is my canonical playerId since it never changes)
5.2. Connect to SpatialOS
This workflow enables me to do several things but most importantly I have a persistent canonical player Id and I can delete player entities as soon as they quit the game, I can associate other entities with my player object based on its canonical player id, and I can defer connecting to Spatial until a sign in was successful.
I hope this helps anyone, and if you would like more information I’d be happy to provide it
Well, it gets into the whole persistent player data area. This is also something I was hoping SpatialOS would offer. I can integrate with Google Firebase or something but having my data “all over the place,” seems to invite problems.
For example, World of Warcraft. I have several characters that have inventories, achievements, skills, etc. When I connect, the player data is loaded into the world for my avatar. For SpatialOS, do I need to do all of the persistency via a separate system? What about changes? If the player spends gold or gains experience points, do I need to sync between the systems?
Problems can arise if I had to do a rollback. In systems I have worked with, when you rollback the world, it also rolls back the players. If the systems are not connected, this seems problematic? For example, Player A hands Player B gold. Something goes wrong and they never get the gold but it disappears from both players inventory. How do you reconcile the issue if player data is stored and managed somewhere else?
I know there are answers to these as you can always roll-your-own. It would be appealing for it all to be in one place is my basic statement. I thought about even having a “place” in the world where players data was stored via entities that never died nor could be found but that seems quite “hackey”.
Some great discussion topics you’ve raised!
The best case study currently would be Worlds Adrift for which the awesome @sami has provided me with some information. The main issues that arise with persistent game data are:
- How do you store the data?
- How do you do reliable transactions?
Reliable transactions are much easier with an external database (which is what Worlds Adrift uses) where the external database will likely have its own guarantees. Storing critical data in the player entities themselves doesn’t make too much sense unless the simulation is truly persistent and leaves your player entities in the world even after logout. The reason for this is that you might want to take a snapshot, take the server down (e.g. for game maintenance) and then restart. When you restart the clients connected from the last snapshot will no longer be connected so you’d have to remove their player entities from the snapshot and place in some kind of external database so it’s ready for when they log in again anyway. This leads onto your suggestion of a persistent ‘database entity’. This would work but would cause some load on the simulation at all times, even when the players whose data is being stored aren’t logged in.
The issue of handing gold between Players A & B seems more like a question on the functionality of Commands which is a really interesting and important topic but probably best saved for another thread. On a basic level I imagine there are multiple ways you verify transactions by exposing some data on each player as a component or in a remote database. This is on top of the fact that Commands have the guarantee of having definitely succeeded on returning successful.
The solution to rolling back will likely depend on your application. If you have a game where a user might have made some real-world transaction then you would want this stored in the database and not rolled back. You could also put timestamps on transactions and rollbacks could be done more selectively.
I’ll try and get someone from our Product team to add to the discussion more!
Hope this has been informative to some extent at least.
Can workers make outbound HTTP(S) requests? For the database to not be tied to the SpatialOS world, the worker will have to make an external call to validate the user can indeed play the game? Or is there some other way to do this?
What I’m struggling with is how to handle validation from client to external system to SpatialOS. I know how to write an authentication system. But getting it to sync with SpatialOS is where I’m confused.
State saving - How with SpatialOS?
I’ll try to pitch in with some details to clear-up some of the apparent mis-understandings that you have (don’t get me wrong, this just means that it’s we who need to improve our documentation, communication, etc.).
Workers can connect to external HTTP(S) endpoints. One of the usages for that is for example to an external third-party database service like Firebase. This is however not how you are going to do authentication because that is not done by the workers (game clients are workers themselves).
Authentication is done before people actually connect to your deployment(s) via the same type of back-end service that allows you to log-in to the deployment console, etc. I’ve described this in some detail in the first halve of my reply to another user. So long story short: the authentication for people will need to be done via a service like Steam, Playfab or others that we have not integrated yet. It might be interesting at some point to be able to integrate your own custom service but that’s just my own speculation and I cannot guarantee anything there, be it on how that would work or when it would potentially be done.
Hope that this helps somewhat!
PS: I’m still writing a more elaborate answer to your other question about data in your new dedicated topic .
I understand; it makes sense for the initial authentication. Given that, how do you ensure the client is authenticated to call the worker? If the worker is not sync’ed with the external authentication system, unauthorized rogue clients can technically connect right?
I do not want to be in the position of trusting the client to tell workers it is legit. Make sense?
Most flows I am used to this process:
- Client calls auth system with credentials
- Auth system returns a token if the client is authenticated
- Client passes token to gaming server
- Gaming server checks to make sure token is valid and confirms client requests
If #2 and #4 are not in sync, how does it work in SpatialOS? I asked about the HTTP(s) call because I was thinking the worker could make a API call to the auth system and see if the token was valid before spawning the player.
Actually you’re anticipating a problem that does not really exist.
The authentication flow currently goes as follows:
- Client contacts auth system with the credentials and the name of the deployment it wants to join
- Auth system checks credentials.
- Auth system contacts the deployment and requests to spin-up an end-point to which the new client can connect.
- Deployment sends back the details (IP & port) of the new end-point to the auth system which forwards them to the client.
- Client connects to the given end-point.
After 5.) you don’t need any further credentials or authentication tokens as the client is the only one on that connection. And if I may insist on one point: your client is a worker itself. Once connected it is not different from any server-side worker as far as SpatialOS is concerned: the client may send commands to server-side workers and they may send commands to the client while both are receiving and sending component updates from the core of the platform. The client only only needs authentication when joining the deployment.
As a developer you don’t even have to care about the internals here as the whole process is done via a single API call in Unity. In C++, in C# or Java this is also via a single call in the
Note that the above flow is only valid for clients (e.g game clients, etc.). Server workers have a different flow in non-Unity SDKs which is also wrapped in a single API call in the
worker::Connection class. Server workers do not need authentication as the deployments fully controls their life-cycle.
State saving - How with SpatialOS?
Ah cool… Great to know. Is there a ClientID I can use that always represents the player regardless of the connection time or the worker involved? Basically a hard-key I can use for off-line storage on a 3rd party system (such as Googles Firebase).
That ClientID would for example be the user ID on the third-party authentication platform that you use (Steam for example). That information will get passed in anyway to your client in order to connect to the deployment. So you can use the same ID then to query Firebase or any other external database that you use for the user’s data.
Does that sounds like a workable solution to you?
@VectorXStudios you can take a look at https://forums.improbable.io/t/how-to-do-playfab-authentication/1707/2 to see how I did the Playfab integration. It also shows how to inject the PlayFab player id using Meta-data
Question… how do you keep from the client telling the server their ID? A “man-in-the-middle” hacker could use this to pretend to be someone they are not if you are relying on the client to be authoritative in this regard.
If I am correct then both services use SSL to communicate; so the contents of your package are not visible. And still: as soon as that player id is compromised then a username and password would be compromised too
If you’d really want to you can also perform authorization from a Worker instead of the client by using a Command with which you send the credentials from the client to the worker but yeah … as I said: potatoes, potatoes. Sending a username and password is equally easy to compromise versus a single secret
I was more concerned if anything is visible to other clients that are connected. For example, is any data passed to the Unity clients that connect regarding entity IDs? Is there a way to ensure code is only visible and executed on the worker (server) side?
I am not entirely sure that I follow you on that last question.
Code is only executed by the worker of which it is part of the code. So if the code in question is only part of a server worker than you are sure that it will only be executed within the deployment.
If I understand correctly then you are worried about data leaking via entities to other players. This is something over which you have full control.
First: Spatial doesn’t use peer-to-peer connections (unless I am mistaken) so data sent by your client won’t go to another client unless you pass that information from your worker back to clients.
Second: you can control, using ACL, which data is readable by which workers (including clients). For example: I have configured parts of my game to be only readable by one very specific worker: the client to which it belongs.
So as @dvanamst says: unless you expose something, it stays on the same worker. (though you can inadvertently expose them through components if you don’t configure your ACL tightly enough).
You answered my question @draconigra, thanks! You are right in that I was worried about clients seeing values for other clients. I realize its a client-server environment but in many engines the client IDs belong to their avatars and are passed in the data stream to everyone. This can enable a nefarious user to view the IDs and forge packets using that ID back to the server. For example, in the Conan MMO, a hacker intercepted the IDs and used them to forge packets telling the client IDs they had fallen from a few thousand feet. This allowed the hacker to instal-kill anyone within range of the packet stream.
From what you are saying, I can keep variables completely hidden from clients and this is what I was getting at. So thanks again!