This document is about: PUN 2
SWITCH TO

PUN Classic (v1), PUN 2 and Bolt are in maintenance mode. PUN 2 will support Unity 2019 to 2022, but no new features will be added. Of course all your PUN & Bolt projects will continue to work and run with the known performance in the future. For any upcoming or new projects: please switch to Photon Fusion or Quantum.

Photon Steam Authentication

Application Setup

Adding Steam as an authentication provider is easy and it could be done in few seconds from your Photon Applications' Dashboard. Go to the "Manage" page of an application and scroll down to the "Authentication" section.

If you add a new authentication provider for Steam or edit an existing one, here the mandatory settings:

  • apiKeySecret: Steam Publisher Web API key. Do not confuse it with Steam User Key. Read more about how to get one here.
  • appid: ID of the Steam game. You can get one after going through Steam Direct process (formerly known as Steam Greenlight).
  • verifyOwnership: Can be true or false: Whether or not to enable Ownership Verification during authentication. This allows you to verify if the user really owns (purchased the game and has it in his library) the game. This step, if enabled, will be performed just after validating the user's session ticket. Enabling this may add extra delay in authentication, so enable it only if you really need it.
  • verifyVacBan: Can be true or false: Whether or not to check if the user has been banned using Valve's Anti-Cheat (VAC) during authentication. Read more here. Enabling this may add extra delay in authentication, so enable it only if you really need it.
  • verifyPubBan: Can be true or false: Whether or not to check if the user has been banned using a Publisher Ban during authentication. Read more here. Enabling this may add extra delay in authentication, so enable it only if you really need it.
  • version: Can be 1 or 2 (default value 1). If version is set to 2 the identity parameter is used when verifying the session ticket. Leave at 1 if you don't use identity.
  • identity: Used if version is set to 2. Steamworks SDK 1.57 added GetAuthTicketForWebAPI which requires an identity parameter. Can be any string identifier (default "photon").

Client Code (Unity)

The client must use Valve's Steamworks API to get a session ticket. This ticket is proof that the client is a valid Steam user.

Steamworks.NET

Steamworks.NET is a popular free and open source Steamworks API wrapper. Follow the instructions listed on this page to import a Unity version of Steamworks.NET.

Get Ticket

Use the following code to get a session ticket using the Steamworks API and convert it to a hex encoded UTF-8 string:

C#

// hAuthTicket should be saved so you can use it to cancel the ticket as soon as you are done with it
public string GetSteamAuthTicket(out HAuthTicket hAuthTicket)
{
    byte[] ticketByteArray = new byte[1024];
    uint ticketSize;
    hAuthTicket = SteamUser.GetAuthSessionTicket(ticketByteArray, ticketByteArray.Length, out ticketSize);
    System.Array.Resize(ref ticketByteArray, (int)ticketSize);
    StringBuilder sb = new StringBuilder();
    for(int i=0; i < ticketSize; i++)
    {
        sb.AppendFormat("{0:x2}", ticketByteArray[i]);
    }
    return sb.ToString();
}

See version and identity parameters description above, if version is set to 2 GetAuthTicketForWebAPI has to be used instead of GetAuthSessionTicket.

Send Ticket

The client must send the user's session ticket (after converting it to a hex encoded UTF-8 string) as a value of a query string key "ticket".

C#

PhotonNetwork.AuthValues = new AuthenticationValues();
PhotonNetwork.AuthValues.UserId = SteamUser.GetSteamID().ToString();
PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Steam;
PhotonNetwork.AuthValues.AddAuthParameter("ticket", SteamAuthSessionTicket);
// connect

Cancel Ticket

It is recommended to cancel or revoke the ticket once authentication is done.

In PUN 2, the first callback to be triggered and where you can cancel the ticket is IConnectionCallbacks.OnConnected:

C#

private void OnConnected()
{
    SteamUser.CancelAuthTicket(hAuthTicket);
}

You could also cancel the ticket in other callbacks like IConnectionCallbacks.OnConnectedToMaster, IConnectionCallbacks.OnCustomAuthenticationFail or even IConnectionCallbacks.OnDisconnected.

Full Snippet

This is a minimal self-contained example and not meant to be copy/pasted in full and used as is in whole.

C#

using Photon.Pun;
using Photon.Realtime;
using Steamworks;

public class MinimalSteamworksPunAuth : MonoBehaviourPunCallbacks
{
    private HAuthTicket hAuthTicket;

    private void Start()
    {
        if (SteamManager.Initialized)
        {
            Connect();
        }
    }

    public void Connect()
    {
        string SteamAuthSessionTicket = GetSteamAuthTicket(out hAuthTicket);
        PhotonNetwork.AuthValues = new AuthenticationValues();
        PhotonNetwork.AuthValues.UserId = SteamUser.GetSteamID().ToString();
        PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Steam;
        PhotonNetwork.AuthValues.AddAuthParameter("ticket", SteamAuthSessionTicket);
        PhotonNetwork.ConnectUsingSettings();
    }
    
    public override void OnConnectedToMaster()
    {
        CancelAuthTicket(hAuthTicket);
    }
    
    public override void OnCustomAuthenticationFailed(string errorMessage)
    {
        CancelAuthTicket(hAuthTicket);
    }
    
    // ticket should be saved so you can use it to cancel the ticket as soon as you are done with it
    private string GetSteamAuthTicket(out HAuthTicket ticket)
    {
        byte[] ticketByteArray = new byte[1024];
        uint ticketSize;
        ticket = SteamUser.GetAuthSessionTicket(ticketByteArray, ticketByteArray.Length, out ticketSize);
        System.Array.Resize(ref ticketByteArray, (int)ticketSize);
        StringBuilder sb = new StringBuilder();
        for(int i=0; i < ticketSize; i++)
        {
            sb.AppendFormat("{0:x2}", ticketByteArray[i]);
        }
        return sb.ToString();
    }
    
  private void CancelAuthTicket(HAuthTicket ticket)
  {
      if (ticket != null)
      {
          SteamUser.CancelAuthTicket(ticket);
      }
  }
}

Facepunch.Steamworks

Facepunch.Steamworks is yet another alternative free and open source implementation of Steamworks API. Follow the instructions listed on this page to import Facepunch.Steamworks.

Get Ticket

Use the following code to get a session ticket and convert it to a hex encoded UTF-8 string:

C#

// authTicket should be saved so you can use it to cancel the ticket as soon as you are done with it
public string GetSteamAuthTicket(out AuthTicket authTicket)
{
    authTicket = SteamUser.GetAuthSessionTicket();
    StringBuilder ticketString = new StringBuilder();
    for (int i = 0; i < authTicket.Data.Length; i++)
    {
        ticketString.AppendFormat("{0:x2}", authTicket.Data[i]);
    }
    return ticketString.ToString();
}

Send Ticket

The client must send the user's session ticket (after converting it to a hex encoded UTF-8 string) as a value of a query string key "ticket".

C#

PhotonNetwork.AuthValues = new AuthenticationValues();
PhotonNetwork.AuthValues.UserId = SteamClient.SteamId.ToString();
PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Steam;
PhotonNetwork.AuthValues.AddAuthParameter("ticket", steamAuthSessionTicket);
// connect

Cancel Ticket

It is recommended to cancel or revoke the ticket once authentication is done.

In PUN 2, the first callback to be triggered and where you can cancel the ticket is IConnectionCallbacks.OnConnected:

C#

private void OnConnected()
{
    ticket.Cancel();
}

You could also cancel the ticket in other callbacks like IConnectionCallbacks.OnConnectedToMaster, IConnectionCallbacks.OnCustomAuthenticationFail or even IConnectionCallbacks.OnDisconnected.

Full Snippet

This is a minimal self-contained example and not meant to be copy/pasted in full and used as is in whole.

C#

using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using UnityEngine;

public class MinimalSteamworksPunAuth : MonoBehaviourPunCallbacks
{
    [SerializeField]
    private int steamAppId;
    private AuthTicket hAuthTicket;

    private void Awake()
    {
        try 
        {
            SteamClient.Init(steamAppId);
        }
        catch (System.Exception e)
        {
            // Couldn't init for some reason - it's one of these:
            //     Steam is closed?
            //     Can't find steam_api dll?
            //     Don't have permission to play app?
        }
    }

    private void Start()
    {
        Connect();
    }

    public void Connect()
    {
        string steamAuthSessionTicket = GetSteamAuthTicket(out hAuthTicket);
        PhotonNetwork.AuthValues = new AuthenticationValues();
        PhotonNetwork.AuthValues.UserId = SteamClient.SteamId.ToString();
        PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Steam;
        PhotonNetwork.AuthValues.AddAuthParameter("ticket", steamAuthSessionTicket);
        PhotonNetwork.ConnectUsingSettings();
    }
    
    public override void OnConnectedToMaster()
    {
        CancelAuthTicket(hAuthTicket);
    }
    
    public override void OnCustomAuthenticationFailed(string errorMessage)
    {
        CancelAuthTicket(hAuthTicket);
    }
    
    // ticket should be saved so you can use it to cancel the ticket as soon as you are done with it
    private string GetSteamAuthTicket(out AuthTicket ticket)
    {
        ticket = SteamUser.GetAuthSessionTicket();
        StringBuilder ticketString = new StringBuilder();
        for (int i = 0; i < ticket.Data.Length; i++)
        {
            ticketString.AppendFormat("{0:x2}", ticket.Data[i]);
        }
        return ticketString.ToString();
    }
    
    private void CancelAuthTicket(AuthTicket ticket)
    {
        if (ticket != null)
        {
            ticket.Cancel();
        }
    }
    
    private void Update()
    {
        SteamClient.RunCallbacks();
    }
    
    private void OnApplicationQuit()
    {
        SteamClient.Shutdown();
    }
}

Change History

June 20, 2023:

  • Added: description for Steam identity usage
Back to top