Server Impersonation
Server Impersonation & Token Exchange
In this How-To we'll look at how to do a request through the LootLocker Game API on a server, acting as a specific user. The server impersonation feature can be used to do something as a player of your game. This can be useful for many reasons such as for example:
Offloading logic from client to server
Moving authoritative calls from the client to the server. In general we will always recommend keeping all write operations in the server. This would be things like submitting scores, rewarding currency, and adding points to a progression.
Delayed actions. Say your idle game loop allows players to perform actions that will take effect after a certain amount of time, while they're not online. Now you can take those actions from your game server.
About Impersonation using Token Exchange
Impersonation on the server can be done in one of two ways. The first we'll discuss is done using a player session token. With this method a token from a Game API session can be used to identify a player. This can should be used in cases where you want to use the Game API in your game client but perform some player actions in the secure context of the server and not allow them on the client.
Prefer token exchange if:
Your player is online when you make actions on behalf of them
The calls you make are triggered by player actions
About Impersonation using Player ULIDs
The other way of impersonating a player is through the use of their ULID. With this method, the server can get an active Game API session token without the user authenticating. This can be used in cases where you either do not want the client to talk directly with LootLocker at all, or if you need to perform actions on behalf of a player disconnected from them being online to authenticate.
Prefer ULID impersonation if:
You need to perform actions on behalf of a player disconnected from their online status. For example:
Delayed actions
Actions triggered from outside of the game such as sending a friend request from a web-page for example
You want to perform mass actions on lists of players
You want to add user moderation actions to the game server
You want to help support recover accounts or in other ways inspect player information
Prerequisites
An Unreal Server Project
An Unreal Game Project
Authentication set up in the console and in the game client. For this example we will default to guest login, but impersonation is authentication agnostic.
Alternatively, you can create the player for a Steam user directly in the server, see Create Server Players
A running LootLocker Server Session.
Implementation
With Token Exchange
The code in this How-To is made to be as transparent and clear as possible, not performant or an example of how you should implement client<->server communication. Adapt the code to your own Server as needed.
1. Start a server session
Refer to the Start Server documentation.
2. Client Code
First you'll need to authenticate your player in the game client and sync the received session token to the server. In this example we will use guest sessions in the interest of simplicity.
ULootLockerSDKManager::GuestLogin(FLootLockerSessionResponse::CreateLambda([](const FLootLockerAuthenticationResponse& sessionResponse) {
if (!sessionResponse.success)
{
// Handle the error case
UE_LOG(<LogCategory>, Error, TEXT("Failed to login: %s"), *sessionResponse.ErrorData.Message);
return;
}
// Replace with your way of syncing the session token to the server
SyncPlayerTokenToGameServer(sessionResponse.session_token);
}));
3. Server Token Exchange
When you get the token from the client you need to exchange the client session token for an impersonated token using the token exchange method. When you have done that you need to add this new session to your copy of the Game SDK.
void OnTokenReceivedFromGameClient(const FString& ClientSessionToken) {
ULootLockerServerForCpp::GameApiTokenExchange(ClientSessionToken,
FLootLockerServerTokenExchangeResponseDelegate::CreateLambda([](const FLootLockerServerTokenExchangeResponse& TokenExchangeResponse)
{
if (!TokenExchangeResponse.Success)
{
// Handle the error case
UE_LOG(<LogCategory>, Error, TEXT("Failed to exchange game client token with error %s"), *TokenExchangeResponse.ErrorData.Message);
return;
}
// Successfully exchanged the token, now add game api session to local copy of game SDK
FLootLockerPlayerData PlayerData;
PlayerData.PlayerUlid = TokenExchangeResponse.Subject_ulid;
PlayerData.Token = TokenExchangeResponse.Access_token;
ULootLockerSDKManager::StartSessionManual(PlayerData);
// Make sure to save the player ulid as that will be used for subsequent requests
TokenExchangeResponse.Subject_ulid;
})
);
}
4. Secure Calls on players behalf
Now that you have the impersonated user in the server, that session can be used to call any of the functions in the Unreal Engine Game SDK, increasing the functionality beyond what the Server SDK is capable of. Here is an example of submitting scores in the game server once an imaginary match finishes on behalf of the impersonated players.
void OnMatchFinished(const FMatchData& MatchData) {
for(const FMatchPlayer& Player : MatchData.Players) {
ULootLockerSDKManager::SubmitScore("", "match_highscore_" + MatchData.MatchId, Player.MatchScore, Player.MatchComment, FLootLockerSubmitScoreResponseDelegate::CreateLambda([](const FLootLockerSubmitScoreResponse& SubmitScoreResponse)
{
if (!SubmitScoreResponse.success)
{
UE_LOG(<LogCategory>, Warning, TEXT("Failed to submit score for player %s with error %s"), *SubmitScoreResponse.PlayerName, *SubmitScoreResponse.ErrorData.Message);
}
else
{
UE_LOG(<LogCategory>, Display, TEXT("Successfully submitted score for player %s with score %d"), *SubmitScoreResponse.PlayerName, SubmitScoreResponse.Score);
}
}), /*IMPORTANT: Make the request execute on behalf of *this* player:*/ Player.PlayerUlid);
}
}
With Player ULID Impersonation
The code in this How-To is made to be as transparent and clear as possible, not performant or an example of how you should implement client<->server communication. Adapt the code to your own Server as needed.
1. Start a Server Session
Refer to the Start Server documentation.
2. Impersonate Using Player ULID
When you want to take actions on behalf of a player, you will need that player's ULID. In this example we will start impersonation from an imaginary server command.
void OnCommandImpersonatePlayer(const FString& PlayerUlid) {
ULootLockerServerForCpp::GameApiUserImpersonation(PlayerUlid,
FLootLockerServerTokenExchangeResponseDelegate::CreateLambda([](const FLootLockerServerTokenExchangeResponse& TokenExchangeResponse)
{
if (!TokenExchangeResponse.Success)
{
// Handle the error case
UE_LOG(<LogCategory>, Error, TEXT("Failed to impersonate player with error %s"), *TokenExchangeResponse.ErrorData.Message);
return;
}
// Successfully impersonated the player, now add game api session to local copy of game SDK
FLootLockerPlayerData PlayerData;
PlayerData.PlayerUlid = TokenExchangeResponse.Subject_ulid;
PlayerData.Token = TokenExchangeResponse.Access_token;
ULootLockerSDKManager::StartSessionManual(PlayerData);
// Make sure to save the player ulid as that will be used for subsequent requests
TokenExchangeResponse.Subject_ulid;
})
);
}
4. Secure Calls on Player's Behalf
This logic will be the same as for the token exchange example in that you simply call the Client SDK methods like you would on the client and make sure to supply the "forPlayerWithUlid" parameter with the ulid you want to execute the request for.
Conclusion
In this How-to we’ve gone through two different ways of allowing the Server to do actions as a player. With the Server API and Game API working hand in hand on your server, you can minimize the risk of tampering from the Game Client as you can reduce the ways that your players can interact with LootLocker. The full Unreal Game SDK and Unreal Server SDK is now at your disposal to be used for trusted and secure operations from your Game Server.
Last updated