Steam Integration - Guide

Install and configure the Steamworks SDK [IDEN-Steam-02]

📘

Install the Steamworks.NET SDK into your project.

The Steamworks.NET SDK is a wrapper around the Steamworks SDK provided from Steam (Valve). You'll need to download the Latest SDK and install it into your project.

Thankfully, it's only a Unity package and you can just import it into Unity like any other package.

In this guide, you will learn the key components to integrating Steam and Beamable.

Steam AppID Setup

You'll need an AppID, which you can acquire from Steam. If you do not have one, you will need to create a new app in the Steam Partner Portal. Once you've created your app, you can find its AppID, which will be a numeric value after the name of your Steam app.

Example: MyAppName (1234567)

You then need to place this AppID in a file that was installed in the root of your project folder. This file is called steam_appid.txt. The root of your project is located in the folder above your Assets folder. It should look like the following, with only the AppID present in the file:

1234567

Setup In Portal (Beta)

There are some additional steps in order to configure Beamable for Steam Integration. You'll need to register your Web API key and AppID in the Beamable portal.

🚧

Beamable Portal is in Beta

To properly configure the Steam Integration you must use the Beamable Portal.

https://beta-portal.beamable.com/

Once you have done this, you can verify that the Steamworks SDK is working by creating any MonoBehaviour and outputting the Steam User ID to the console.

Log in to [Steam Partner Portal] and use the dropdown option to Manage Groups. In your main group, you will need to create a Web API Key if you have not created one yet. It will be located as an option in the right-hand side bar. If you have already created one, then it will be displayed in the side bar as well.

Follow these steps in the Beamable Portal:

Steps

Log in to Beamable Beta Portal

Navigate to the Realm Configuration page

Create a new Key in the configuration by clicking on +Config and name it "steam" (all lower-case) in the namespace field.

Create 3 KVP values: sandbox , appid , key

Enter "true" for the sandbox value

Use your Steam AppID for the appid value

Enter your WebAPI key for the key value

While the above steps are not needed to test that the Steamworks SDK is working, they are critical in order for the Beamable Steam integration to work properly.

void Start(){
    var steamUserID = SteamUser.GetSteamID().ToString();
    Debug.Log($"SteamUserID:{steamUserID}");
}

You should see that your Steam ID is printed to the console.

📘

Using Steamworks

Be sure to include the Steamworks.NET SDK in the files you are working with.
using Steamworks;

Getting Steam Session Ticket

You'll need to acquire a Steam Session Ticket to validate. In the example below, we are using the SteamUser.GetAuthSessionTicket() function of the Steamworks SDK to accomplish this. You can copy and paste the following into your code as-is to get your Steam Session Ticket:

/// <summary>
/// Get the Auth ticket for the current Steam User
/// </summary>
/// <param name="hAuthTicket"></param>
/// <returns>an string auth ticket provided from steam</returns>
private Promise<string> GetSteamAuthTicket()
{
    var promise = new Promise<string>();
    var steamAuthTicketBuffer = new byte[1024];
    uint steamAuthTicketBufferSize = 1024;

    Callback<GetAuthSessionTicketResponse_t>.Create(_ =>
    {
        var usedBytes = new List<byte>(steamAuthTicketBuffer).GetRange(0, (int) steamAuthTicketBufferSize).ToArray();
        var ticket = BitConverter.ToString(usedBytes).Replace("-", string.Empty);
        promise.CompleteSuccess(ticket);
    });

    SteamUser.GetAuthSessionTicket(steamAuthTicketBuffer, (int) steamAuthTicketBufferSize, out steamAuthTicketBufferSize);

    return promise;
}

You can then call this promise as an async/await task:

var ticket = await GetSteamAuthTicket();

Validating the Steam Auth Session Ticket with Beamable

The next step you need to take is to validate the Session Ticket with Beamable. Beamable will return whether that ticket is valid or not. You can use the function below as-is:

/// <summary>
/// Validate a Steam ticket with the Beamable service
/// </summary>
/// <param name="ticket"></param>
/// <returns>True if Valid, False if error or failed validation</returns>
private Promise<bool> BeamableValidateSteamTicket(string ticket)
{
    var promise = new Promise<bool>();
    
    _beamContext.Requester.Request<Beamable.Common.Api.EmptyResponse>(
        Beamable.Common.Api.Method.POST,
        $"/basic/payments/steam/auth",
        new SteamTicketRequest(ticket))
    .Then(f =>
    {
        promise.CompleteSuccess(true);
    })
    .Error(ex=>{
        Debug.LogError(ex);
        promise.CompleteSuccess(false);
    });
    
    return promise;
}

You can call this promise using async/await:

var isSteamTicketValid = await BeamableValidateSteamTicket(ticket);

Login to Beamable with 3rd Party (Steam)

Much like our other 3rd Party authentication methods, you will use the three main functions in the Beamable SDK: LoginThirdParty, RegisterThirdPartyCredentials, CreateUser.

To use these services, you must convert the Steam Auth Ticket to the proper format in order for Beamable to recognize it.

var request = new AuthenticateUserRequest(SteamUser.GetSteamID().ToString(), ticket);
var steamRequest = JsonUtility.ToJson(request);
var encodedRequest = Encoding.UTF8.GetBytes(steamRequest);
var token = Convert.ToBase64String(encodedRequest);

In the following sections, you will see that we use the above code to convert the ticket to a Beamable token.

Handle Various Flow Scenarios

Now that we have the Steam Session Token, we need to account for 3 different scenarios:

New Player
Returning Player already linked to Steam
Returning Player linking their account with Steam

We can account for this by determining if we need to:

Switch Player - Player wants to switch credentials to a new Player
Create New Player - Player wants to Create a new Player account
Attach To Current Player - Player wants to Attach this 3rd Party Login to an already authenticated Player.

/// <summary>
/// Handle various scenarios for Steam Login, from Create User to Login.
/// </summary>
/// <param name="ticketResponse"></param>
private void HandleSteamLogin(string ticket, bool available)
{
    var userHasCredentials = _beamContext.Api.User.HasThirdPartyAssociation(ThirdParty);
    var shouldSwitchUsers = !available;
    var shouldCreateUser = available && userHasCredentials;
    var shouldAttachToCurrentUser = available && !userHasCredentials;

    if (shouldSwitchUsers)
    {
        LoginWithSteam(ticket);
    }
    if (shouldCreateUser)
    {
        CreateAndRegister(ticket);            
    }
    if (shouldAttachToCurrentUser)
    {
        RegisterThirdPartyToken(ticket);
    }
}

Below you will find the three helper functions: LoginWithSteam, CreateAndRegister, and RegisterThirdPartyToken

/// <summary>
/// Login with steam token and apply the current token 
/// </summary>
/// <param name="ticket"></param>
private void LoginWithSteam(string ticket)
{
    var request = new AuthenticateUserRequest(SteamUser.GetSteamID().ToString(), ticket);
    var steamRequest = JsonUtility.ToJson(request);
    var encodedRequest = Encoding.UTF8.GetBytes(steamRequest);
    var token = Convert.ToBase64String(encodedRequest);
    _beamContext.Api.AuthService.LoginThirdParty(ThirdParty, token, false)
        .FlatMap(_beamContext.Api.ApplyToken)
        .FlatMap(_ => _beamContext.Api.AuthService.GetUser())
        .Then(_beamContext.Api.UpdateUserData);        
}
/// <summary>
/// Create a new user and associate the Steam ticket with that user.
/// </summary>
/// <param name="ticket"></param>
private void CreateAndRegister(string ticket)
{
    var request = new AuthenticateUserRequest(SteamUser.GetSteamID().ToString(), ticket);
    var steamRequest = JsonUtility.ToJson(request);
    var encodedRequest = Encoding.UTF8.GetBytes(steamRequest);
    var token = Convert.ToBase64String(encodedRequest);
    _beamContext.Api.AuthService.CreateUser()
        .FlatMap(_beamContext.Api.ApplyToken)
        .FlatMap(_ => _beamContext.Api.AuthService.RegisterThirdPartyCredentials(ThirdParty, token))
        .Then(_beamContext.Api.UpdateUserData);
}
/// <summary>
/// Register third party token for the steam user with Beamable
/// </summary>
/// <param name="ticket"></param>
private void RegisterThirdPartyToken(string ticket)
{
    var request = new AuthenticateUserRequest(SteamUser.GetSteamID().ToString(), ticket);
    var steamRequest = JsonUtility.ToJson(request);
    var encodedRequest = Encoding.UTF8.GetBytes(steamRequest);
    var token = Convert.ToBase64String(encodedRequest);
    
    _beamContext.Api.AuthService.RegisterThirdPartyCredentials(ThirdParty, token)
        .Then(_beamContext.Api.UpdateUserData);
}

Putting it all together

In the Start method of your MonoBehaviour, you can do something like the following:

async void Start()
{
    _beamContext = BeamContext.Default;
    await _beamContext.OnReady;
    Debug.Log($"Beamable User ID: {_beamContext.PlayerId}");
    if (!SteamManager.Initialized) return;
    var steamUserID = SteamUser.GetSteamID().ToString();
    Debug.Log($"SteamUserID:{steamUserID}");
    
    var ticket = await GetSteamAuthTicket();
        var isValid = await BeamableValidateSteamTicket(ticket);
  
    Debug.Log($"Current Steam Ticket: {ticket}");
    
    if (isValid)
    {
        Debug.Log("Steam Token was Validated");
    }
    else
    {
        Debug.LogError("Steam Token validation failed");
    }

    HandleSteamLogin(ticket, isValid);
}

Did this page help you?