Creating your own authentication server using the Platform SDK (alpha)
Introduction
When a game client wants to connect to your SpatialOS deployment, it is initially untrusted and must authenticate via our services in order to be admitted to the deployment.
This guide describes how to create your own authentication server which integrates your chosen authentication method/provider with the SpatialOS authentication service. This allows you to write your own logic to validate the identity of players and control which deployments they can connect to.
Overview
Integrating a third-party or bespoke authentication provider with SpatialOS involves supporting two flows: an authentication flow and a login flow.
Authentication flow
One of the first things a game client does when it starts is go through the authentication flow. This verifies that the player is permitted to play the game, for example, by checking that the player has an account.
The steps below outline how an authentication server should interact with your game client. You need to implement your authentication server and game client to follow these general steps.
- The game client requests to be authenticated through your authentication server. This request should contain enough information for you to be able to validate their identity (for example a username and password).
- Your authentication server verifies the player’s credentials using a third-party or custom authentication provider.
- The server must then use the SpatialOS Platform SDK to generate a
PlayerIdentityToken
using a unique identifier for the player and your SpatialOS project’s name. - Your authentication server returns this
PlayerIdentityToken
to the game client. The game client can now use this token to prove its identity within SpatialOS until the token expires (by default a token is valid for 24 hours).
Login flow
Once a game client has a PlayerIdentityToken
it can go through the login flow. This where your login server decides which deployment a player should log in to, and creates a LoginToken
that allows the player to log into that specific deployment.
The steps below outline how a login server should interact with your game client. You need to implement your login server and game client to follow these general steps.
- The game client requests to log in through your login server using its
PlayerIdentityToken
. - Your login server uses the SpatialOS Platform SDK to validate and decode the
PlayerIdentityToken
. - Your login server must verify that the
PlayerIdentityToken
’s provider and project name match what you expect. - Your login server decides which deployment the player should join. For example, you can implement a matchmaking system, choose a deployment based on the player’s location, or present a list of deployments for the player to choose from themselves.
- Your login server uses the Platform SDK to create a
LoginToken
for the chosen deployment and returns this to the game client. - The game client uses this
LoginToken
and itsPlayerIdentityToken
to connect to the SpatialOS deployment.
Creating your own authentication server with SpatialOS
1. Obtaining a service account with the necessary permissions
In order to issue PlayerIdentityTokens and LoginTokens, your authentication/login server must have a service account with read and write access for the {prj, <project_name>, playerauth}
path.
Your login server also needs read access for the {prj, <project_name>, dpl, *
path to be able to list currently running deployments.
You can create a service account with these permissions using the Platform SDK service account service.
2. Generating a PlayerIdentityToken
Once your authentication server has verified a client’s identity, you must call the PlayerAuthService
’s CreatePlayerIdentityToken
method with the player’s unique identifier, your SpatialOS project name, and a provider name. This provider can be any string and allows you to identify (for example, on your login server) where a player acquired their PlayerIdentityToken
.
The PlayerIdentityToken
is a signed token which the game client can use as its identity when making requests to SpatialOS services. By default, this token is valid for 24 hours, after which the client must re-authenticate with your authentication server.
Using the C# Platform SDK a PlayerIdentityToken
can be created like so:
PlayerAuthServiceClient playerAuthServiceClient = PlayerAuthServiceClient.Create(credentials: CredentialWithProvidedToken);
var playerIdentityTokenResponse = playerAuthServiceClient.CreatePlayerIdentityToken(
new CreatePlayerIdentityTokenRequest
{
Provider = "your_provider",
PlayerIdentifier = "unqiue_player_identifier",
ProjectName = "your_project_name"
});
3. Generating a LoginToken
Once the client has received a PlayerIdentityToken
from your authentication server and sent it in a request to your login server, they now need to be assigned to a specific deployment.
The first step your login server should do is use the Platform SDK DecodePlayerIdentityToken
method to read the contents of the PlayerIdentityToken
. The login server should verify the validity of the token using the decoded fields. This includes, as a minimum, ensuring that the provider and project associated with the token match the values set by your authentication server, and that the token has not expired.
At this point you can implement business logic to, for example, perform matchmaking of players, allow players to select the deployment they want to join, or to host a queue for players to wait in before they can play.
This decision can be based on the player identifier and metadata fields present in the PlayerIdentityToken
. For example, you may have a set of deployments running newer builds of your game that should only be accessible to players who have signed up to your beta tester program.
Once your login server has decided on a specific deployment for a client to join, it must call the PlayerAuthService
’s CreateLoginToken
method to create a signed LoginToken
. This LoginToken
is short-lived (by default, valid for 15 minutes) and proves to SpatialOS services that a given game client (identified by their PlayerIdentityToken
) is permitted to join a given deployment.
Using the C# Platform SDK:
PlayerAuthServiceClient playerAuthServiceClient = PlayerAuthServiceClient.Create(credentials: CredentialWithProvidedToken);
var decodePlayerIdentityTokenResponse = playerAuthServiceClient.DecodePlayerIdentityToken(
new DecodePlayerIdentityTokenRequest
{
PlayerIdentityToken = playerIdentityTokenFromGameClient
});
// Here you should verify that the decoded PlayerIdentityToken's provider and project name match
// the values set by your authentication server and that the token has not expired
var createLoginTokenResponse = playerAuthServiceClient.CreateLoginToken(
new CreateLoginTokenRequest
{
PlayerIdentityToken = playerIdentityTokenFromGameClient,
DeploymentId = chosenDeploymentId,
WorkerType = "game_client" // This should match the worker type of the game client
});
4. Connecting to the deployment
Once your game client has received both a PlayerIdentityToken
and a LoginToken
it can connect to the deployment using the Worker SDK. This is done through the Locator.
Set the LocatorParameters
(C#/C++)’s PlayerIdentity
to a PlayerIdentityCredentials
value containing the PlayerIdentityToken
and LoginToken
obtained from your authentication/login server in the previous steps.
When using your own authentication, any queuing should be implemented by your login server before it issues a LoginToken
. Once a client has a LoginToken
it will be able to immediately connect to the deployment (assuming that the maximum capacity and join rate of the deployment have not been reached).
Using the Worker SDK in C#:
var locatorParameters = new LocatorParameters {
PlayerIdentity = new PlayerIdentityCredentials {
PlayerIdentityToken = playerIdentityTokenResponse.PlayerIdentityToken,
LoginToken = createLoginTokenResponse.LoginToken
}
};
var locator = new Locator(LocatorServerAddress, LocatorServerPort, locatorParameters);
using(var connectionFuture = locator.ConnectAsync(new ConnectionParameters {
WorkerType = "game_client", // This should match the worker type of your game client
Network = {
ConnectionType = NetworkConnectionType.Tcp,
UseExternalIp = true
}
})) {
var connFuture = connectionFuture.Get(Convert.ToUInt32(Defaults.ConnectionTimeoutMillis));
if (!connFuture.HasValue || !connFuture.Value.IsConnected)
throw new Exception("No connection or connection not established");
Console.WriteLine($"Assigned worker ID: {connFuture.Value.GetWorkerId()}");
}
Migrating to the new Platform SDK (alpha) integration
The largest conceptual change between the deprecated integration and the new (alpha) integration described above is the separation of PlayerToken
s into a PlayerIdentityToken
and a LoginToken
.
This separation reflects the differences between the authentication of players and the assigning of players to deployments:
- Players should only need to authenticate with your game (for example, prove they have a valid username and password) once per session even if this session involves connecting to multiple different deployments. As a result
PlayerIdentityToken
s:- are not tied to a specific deployment.
- are longer-lived than
LoginToken
s (by default they are valid for 24 hours).
- Permission to log into a deployment should only last long enough for the player to establish their connection and should only allow connection to a specific deployment. As a result
LoginToken
s:- are short-lived (by default, they are valid for only 15 minutes).
- are valid only for a specific deployment ID.
When migrating your authentication server to the new authentication system there are two options:
- A simple migration which moves your game client and server to use the new authentication API methods but otherwise requires minimal changes to how your game client and server interact with each other.
- A full migration which additionally changes how your game client and server work to benefit from the separation of authentication (obtaining a
PlayerIdentityToken
) and requesting to join a deployment (obtaining aLoginToken
).
You can find more details about each of these options below.
Simple migration
The simplest migration option (requiring minimal changes to your game client) involves modifying your authentication server to generate and return both a PlayerIdentityToken
and LoginToken
upon each authentication request from your game client.
For your authentication provider, this requires making two calls to the Platform SDK (specifically, the CreatePlayerIdentityToken
and CreateLoginToken
methods) rather than the single CreatePlayerToken
method. You should ensure that the service account you are using has the correct permissions to call these methods as described here.
For your game client this only requires modifying your authentication code to expect both of these tokens in the response from your server, and changing your Worker SDK LocatorParameters
to the values described here.
This simple migration achieves many of the benefits of the new authentication flow:
- You gain fine-grained control over which deployments in your project a player can connect to.
- In the future, the trusted player identifier field in the
PlayerIdentityToken
will be accessible in the Runtime allowing your server logic to link a player within the deployment to their identity outside the deployment.
Full migration
To fully migrate to the new authentication system, your game client needs to have separate calls to your authentication provider for authentication and for logging in to a deployment. This process is sufficiently different from the one described above that it is preferable to follow the new guide in full rather than attempt to adapt your existing solution.
Although full migration has a larger development cost than the simple option, it comes with the benefits that:
- Players can authenticate with their client starts and then log into and move between deployments without having to re-authenticate each time.
- By running separate authentication and login servers you can horizontally scale these by different amounts. For example, you can run more instances of your login server because it runs intensive matchmaking logic as opposed to your authentication server which performs much less computation.