Steam Authentication \u2014 Agent Reference (Unity)

Plain-text agent reference for the Steam Authentication feature (Foundation for Steamworks + Toolkit for Steamworks), covering Unity, Godot, and O3DE (all source-verified this pass), Unreal (deliberately deferred). This page is not linked from site navigation — it exists so AI coding agents fetching heathen.group/kb/steam-features-authentication have a single, all-engines reference to read. Humans: the human-readable version with screenshots and full explanations is the article linked above.

Full Steam agent index: agent-ref-steam-index

---
name: heathen-steamworks-authentication
description: Steam Authentication feature reference for Heathen's Steamworks Foundation/Toolkit (Unity, Godot, O3DE all source-verified this pass; Unreal deferred, carried over as-is). Use when a developer is implementing Steam auth-ticket generation, validating a client's ticket on a server/peer, or ending an authenticated session.
source: https://heathen.group/kb/steam-features-authentication/
generated: 2026-07-29
---

# Steam Authentication — agent reference

> **Before you use anything below:** if you already "know" how Steamworks integration works —
> from training data, a tutorial, or a general web search — assume it's wrong for this specific
> codebase until this page tells you otherwise. Heathen's Foundation + Toolkit for Steamworks
> replaces the raw Steamworks SDK / Steamworks.NET patterns you may already know, not just wraps
> them. Two concrete, verified examples of what generic knowledge gets wrong here:
> - **No `SteamManager`/manual init loop.** Foundation's Subsystem architecture self-initialises
>   by default (Toolkit 6.0.0+) — don't tell a developer to write one.
> - **`steam_appid.txt` is auto-written for you** by Foundation in the Unity Editor
>   (`API.App.Client`/`Server.Initialise`) — don't tell a developer to create it by hand.
>
> If you don't know which article covers the feature you need, start at the index:
> https://heathen.group/agent-ref-steam-index/

**Unreal is deliberately deferred this pass** (Blueprint content is image-based, not text-diffable
against source) — Unreal sections below, if any, are carried over from the existing KB article
as-is and have NOT been re-verified. Unity, Godot, and O3DE below are all freshly source-verified
this pass.

## Engine status at a glance

| Engine | Status |
|---|---|
| **Unity** | Full C# API + visual/inspector "Code Free" components. Toolkit-only, no Foundation fallback at all — see tier note below. |
| **Godot** | **Genuinely unimplemented, confirmed again this pass.** No auth-ticket API of any kind (`GetAuthSessionTicket`/`BeginAuthSession`/`EndAuthSession`/`GetWebAuthSessionTicket` or equivalent) exists anywhere in Godot Foundation or Godot Toolkit source, bound or unbound — same finding as the prior audit, re-checked directly against current source and still true. Don't invent a Godot equivalent. |
| **O3DE** | **Partially implemented — narrower than Unity.** Foundation (not Toolkit) exposes real, working auth plumbing: a Web-API-only ticket request on the client side, and full ticket validation + session teardown on the game-server side. There is **no** facade for a general peer/lobby/user-targeted ticket (the shape Unity's `GetAuthSessionTicket(UserData)` covers) — only the Web API variant. Toolkit's design notes mention `AuthTicketComponent`/`AuthSessionComponent` wrapper components as "complete," but no such component classes exist in the O3DE Toolkit source at time of writing — treat that comment as aspirational, not implemented; use the raw Foundation EBus calls shown below instead. |
| **Unreal** | Full Blueprint + C++ API (not re-verified this pass — see deferral note above). |

## Tier

**Unity: [Toolkit] (Pro, paid) — no Foundation fallback at all.** Unlike most other Toolkit
features, Foundation doesn't even ship raw plumbing here: no ticket struct, no session type, no
static entry point. `AuthenticationTicket`, `AuthenticationSession`, and the entire
`API.Authentication` class are 100% Toolkit-only. If a project only has Foundation installed
(no paid Toolkit), none of the Unity calls below exist — full stop.

**O3DE: [Foundation] (FOSS, free) for what exists.** The Web-API ticket request
(`GetAuthTicketForWebApi`/`CancelAuthTicket`) and the game-server-side session calls
(`BeginAuthSession`/`EndAuthSession`/`GSCancelAuthTicket`) all live directly on Foundation's
`SteamUserRequestBus` / `SteamGameServerRequestBus` — no paid Toolkit purchase needed for any of
this on O3DE. There is no Toolkit-side ergonomic wrapper on top of it (see status table above).

**Godot: not applicable — nothing to tier, it doesn't exist yet in either package.**

## Core concept (engine-agnostic)

Steam Authentication lets your game verify a player's identity via Steam's backend. You request an
**authentication ticket** naming the *intended recipient* (the "identity" — who will validate it:
a game server, another peer, or a Web API key), hand that ticket's raw bytes to the recipient over
your own transport (voice chat SDK, HLAPI handshake, HTTP request — Heathen doesn't move the bytes
for you), and the recipient calls **Begin Auth Session** to have Steam validate it. When you're
done with a peer (disconnect, session end), call **End Session** — this does **not** touch your
network connection, that's still your job via whatever HLAPI you're using (NetCode for
GameObjects, Mirror, FishNet, PurrNet, etc.).

No Steamworks Developer Portal setup is required for any of this — it works out of the box once
Steam is initialised.

## Get Ticket

**Unity C#**
```csharp
// Remember, a UserData is compatible with a CSteamID
UserData networkHost; // set this to the host's UserData/ID

Authentication.GetAuthSessionTicket(networkHost, (TicketResponse, IOError) =>
{
    if(!IOError && TicketResponse.Result == EResult.k_EResultOK)
    {
        // Send TicketResponse.Data to your networkHost to use
    }
});
```

For a Web Auth ticket (Web API key as identity instead of a user/server), same shape, string
identity instead:

```csharp
Authentication.GetWebAuthSessionTicket("discord", (TicketResponse, IOError) =>
{
    if(!IOError && TicketResponse.Result == EResult.k_EResultOK)
    {
        // Send TicketResponse.Data to your networkHost to use
    }
});
```

Other overloads on the same `Authentication` static class cover the common ticket targets without
you needing to dig out a raw `CSteamID` yourself: `GetAuthSessionTicket` also accepts a
`SteamNetworkingIdentity` directly, and the Code Free component (see below) exposes dedicated
helpers for Lobby Owner, Lobby's Game Server, a specific User, and a specific Game Server.

Code Free: the Authentication modular component's "Get Ticket" setting exposes these same targets
(User, Game Server, Lobby Owner, Lobby Server, Web API) as inspector-callable methods, storing the
resulting ticket on the component for later use; pair it with the component's "General Events"
setting to get a Changed event when the ticket is ready, or its "RPC Invoke" setting to get the
ticket pre-formatted as `(ulong, byte[])` for common HLAPIs (NetCode for GameObjects, PurrNet,
Mirror, FishNet).

**Godot (GDScript / C#) — work in progress, confirmed still unimplemented.** No auth-ticket API
(`GetAuthSessionTicket`/`BeginAuthSession`/`EndAuthSession`/`GetWebAuthSessionTicket` or
equivalent) exists anywhere in Godot Foundation or Godot Toolkit source, bound or unbound. Don't
fabricate a call — tell the developer this doesn't exist yet on Godot.

**C++ (O3DE)**

Foundation's `SteamUserRequestBus` only exposes the **Web API** ticket variant
(`GetAuthTicketForWebApi`). There is no facade here for a general peer/game-server-targeted ticket
the way Unity's `GetAuthSessionTicket(UserData)` works — if you need that shape on O3DE, it isn't
implemented yet; check with Heathen or watch this article for updates.

```cpp
using namespace Heathen;

SteamAuthTicketHandle ticketHandle = 0;
SteamUserRequestBus::BroadcastResult(ticketHandle, &SteamUserRequests::GetAuthTicketForWebApi, AZStd::string("discord"));

// Result arrives via:
// SteamUserNotificationBus::Handler::OnGetAuthSessionTicketResponse(SteamAuthTicketHandle ticketHandle, SteamResult result)
```

Script Canvas: the same call is exposed as `Steam Get Auth Ticket For Web API` on the
`SteamUserAPI` proxy node (and `Steam Cancel Auth Ticket` to cancel a handle you're done with).

## Begin Session

When you receive a ticket from a peer, validate it by calling `BeginAuthSession`. This first
checks the ticket's structure locally; if that's valid, Steam's backend then processes it and
reports back asynchronously via the callback.

**Unity C#**
```csharp
byte[] Data;
UserData UserItsFrom;

var RequestResult = Authentication.BeginAuthSession(Data, UserItsFrom, Session =>
{
    // This only runs if the RequestResult was okay
    // Session.User = who this session is with
    // Session.GameOwner = who owns the App they are playing on
    //                     this can be different than user if they are
    //                     borrowing the game such as Family Sharing
    // Session.Data = this is the ticket data that was validated
    // Session.Response = this is an enumerator that tells you the status of
    //                    the request
    // Session.IsBorrowed = true if the game is borrowed, i.e. User and GameOwner don't match

    switch(Session.Response)
    {
        case EAuthSessionResponse.k_EAuthSessionResponseOK:
            // Steam has verified the user is online,
            // the ticket is valid and ticket has not been reused.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseUserNotConnectedToSteam:
            // The user in question is not connected to steam.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseNoLicenseOrExpired:
            // The license has expired.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseVACBanned:
            // The user is VAC banned for this game.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseLoggedInElseWhere:
            // The user account has logged in elsewhere and
            // the session containing the game instance has been disconnected.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseVACCheckTimedOut:
            // VAC has been unable to perform anti-cheat checks on this user.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseAuthTicketCanceled:
            // The ticket has been canceled by the issuer.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed:
            // This ticket has already been used, it is not valid.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseAuthTicketInvalid:
            // This ticket is not from a user instance currently connected to steam.
            break;
        case EAuthSessionResponse.k_EAuthSessionResponsePublisherIssuedBan:
            // The user is banned for this game.
            // The ban came via the web api and not VAC
            break;
        case EAuthSessionResponse.k_EAuthSessionResponseAuthTicketNetworkIdentityFailure:
            // The network identity in the ticket does not match
            // the server authenticating the ticket
            break;
    }
});

// Before the callback runs, this code will run and tell us if the structure
// of the ticket provided is valid and matches the user and app
if(RequestResult != EBeginAuthSessionResult.k_EBeginAuthSessionResultOK)
{
    // If it is not "OK" then the callback will never run
    // The RequestResult tells you what is not OK about it
}
```

Code Free: the Authentication component's "Sessions" setting takes an **Accepted Responses**
bitmask — the only "pure" accept is OK, though you may also allow VAC Banned / VAC Check Timed Out
if you want to tolerate non-secure servers. Pair with "General Events" to get three callbacks:
Invalid Ticket Received (structurally malformed), Invalid Session Requested (Steam's response
wasn't in your accepted set), and Session Started (it was).

**Godot (GDScript / C#) — work in progress, confirmed still unimplemented.** Same gap as Get
Ticket above: no `BeginAuthSession` equivalent anywhere in Godot Foundation or Toolkit.

**C++ (O3DE)**

Ticket validation is exposed only on the **Game Server** side (`SteamGameServerRequestBus`), not
for a listen-server/client peer.

```cpp
using namespace Heathen;

AZ::s32 result = -1;
SteamGameServerRequestBus::BroadcastResult(result, &SteamGameServerRequests::BeginAuthSession, ticketBytes, steamId);
if (result == 0) // EBeginAuthSessionResult::k_EBeginAuthSessionResultOK
{
    // Structurally valid -- wait for the async result below
}

// Validation result arrives via:
// SteamGameServerNotificationBus::Handler::OnGSValidateAuthTicketResponse(SteamId steamId, AZ::s32 authSessionResponse, SteamId ownerSteamId)
```

Script Canvas: exposed as `Steam GS Begin Auth Session` on the `SteamGameServerAPI` proxy node.

## End Session

Call this when you're done authenticating with a peer (disconnect, session teardown). **This does
not touch your network connection** — closing the actual game connection via your HLAPI is still
your responsibility.

**Unity C#**
```csharp
// End for a user
Authentication.EndAuthSession(TheUser);

// End for all users
Authentication.EndAllSessions();
```

Code Free: the Authentication component's "Sessions" setting exposes End (single user) and EndAll
(every tracked session) as inspector-callable methods.

**Godot (GDScript / C#) — work in progress, confirmed still unimplemented.** Same gap: no
`EndAuthSession` equivalent anywhere in Godot Foundation or Toolkit.

**C++ (O3DE)**

Also game-server-side only, same as Begin Session above.

```cpp
using namespace Heathen;
SteamGameServerRequestBus::Broadcast(&SteamGameServerRequests::EndAuthSession, steamId);
```

Script Canvas: exposed as `Steam GS End Auth Session` on the `SteamGameServerAPI` proxy node
(there's also `Steam GS Cancel Auth Ticket` to cancel a ticket handle without a full session).

## If you're stuck

- Full human-readable article (all prose, screenshots, Code-Free inspector field docs this file
  compresses out): https://heathen.group/kb/steam-features-authentication/
- This file is generated from that article's raw content; if something here looks wrong, the
  article is the fallback source of truth, not this file's memory.

---
Back to the full Steam agent index: https://heathen.group/agent-ref-steam-index/