Skip to content

Steam App Auth

Alex Corn edited this page Feb 20, 2020 · 3 revisions

As of v3.25.0, a SteamUser can retrieve Steam app tickets.
This is currently experimental. The API is not finalized and may change at any time.

Ticket Overview

A typical app ticket consists of a GC token, a session header, and an app ownership ticket. All three parts are sent to game servers or peers (in P2P games) for validation.

GC Token

GC stands for "game connect" here. This is a token assigned by Steam when you connect which is assigned to your login session. These aren't assigned to any app until you "activate" a ticket. They're used to make tickets unique.

Session Header

This part isn't particularly interesting. It contains your external IP and some uninteresting stuff like how many tickets you've retrieved this session.

App Ownership Ticket

This part of the ticket is signed by Steam and is valid for a longer period of time, usually a couple weeks. It proves to your peer that you own the game you're trying to authenticate for. It can be reused many times with different GC tokens.

It contains things like your SteamID, the ID of the app it was assigned for, your external and internal IP addresses, the times when the ticket was generated and when it expires, the licenses you own which grant you this game, any DLC you own, and a signature.

Since this part of the ticket is signed, has an expiration date, and can be reused, there's no need to send it to Steam for validation, so it's validated locally.

Static Methods

parseAppTicket(ticket)

  • ticket - A Buffer containing the app ticket you want to parse
  • allowInvalidSignature - Optional. Pass true to get back data even if the ticket has no valid signature. Defaults to false.

Also available as its own module.

This is a static method, so you should use it like this:

const SteamUser = require('steam-user');
let parsed = SteamUser.parseAppTicket(ticket);

Parses an app ticket. You can either parse a full appticket (GC token + session header + ownership ticket), or just an ownership ticket.

On success, returns an object containing these properties:

  • authTicket - A Buffer containing the part of the ticket that's sent to Steam for validation
  • gcToken - A string containing a 64-bit number which is the ticket's "GC token" (GC stands for "game connect")
  • tokenGenerated - A Date object containing the time when this ticket's GC token was generated
  • sessionExternalIP - A string containing the ticket owner's external IP address (as reported by Steam) at time of connection
  • clientConnectionTime - Time in milliseconds the ticket owner was connected to Steam when they generated this ticket (?)
  • clientConnectionCount - Number of tickets generated by the ticket owner for this Steam connection (?)
  • version - The version of the app ownership ticket
  • steamID - The ticket owner's SteamID, as a SteamID object
  • appID - The ID of the app this ticket authenticates
  • ownershipTicketExternalIP - A string containing the external IP address of the ticket owner as reported by Steam at the time when the ownership ticket was assigned
  • ownershipTicketInternalIP - Same as above but for their internal IP. If the ticket was generated by steam-user then this may be random
  • ownershipFlags - A number containing some (probably uninteresting) flags
  • ownershipTicketGenerated - A Date object containing the time when this ticket's ownership ticket was assigned
  • ownershipTicketExpires - Same as above but for when the ownership ticket expires
  • licenses - An array of integers containing the package IDs for all the licenses the ticket owner owns which grant them this app
  • dlc - An array of objects, each of which contains:
    • appID - The AppID of the piece of DLC
    • licenses - An array of integers containing the package IDs for all the licenses the ticket owner owns which grant them this DLC. Seems to not work right now.
  • signature - A Buffer containing the signature for the app ownership ticket (uninteresting to you)
  • isExpired - A boolean indicating whether the app ownership ticket is expired
  • hasValidSignature - A boolean indicating whether the app ownership ticket signature is valid
  • isValid - A boolean indicating whether the app ownership ticket is valid
    • If allowInvalidSignature is true and the signature is missing, this will be true if the ticket is not expired!

Returns null if unable to decode any part of the ticket.

parseEncryptedAppTicket(ticket, encryptionKey)

  • ticket - A Buffer containing the encrypted app ticket you want to parse
  • encryptionKey - A Buffer or a hex string containing the encryption key for the app to which this ticket belongs

Also available as its own module.

v3.26.0 or later is required to use this function

If you happen to be the developer of an app, you could use this to decrypt one of your encrypted app tickets. You'll need the encrypted app ticket key for the app to which the ticket you supply belongs. This happens 100% locally, so there's no need to be able to reach Steam to do this.

  • version - The version of the app ownership ticket
  • steamID - The ticket owner's SteamID, as a SteamID object
  • appID - The ID of the app this ticket authenticates
  • ownershipTicketExternalIP - A string containing the external IP address of the ticket owner as reported by Steam at the time when the ownership ticket was assigned
  • ownershipTicketInternalIP - Same as above but for their internal IP. If the ticket was generated by steam-user then this may be random
  • ownershipFlags - A number containing some (probably uninteresting) flags
  • ownershipTicketGenerated - A Date object containing the time when this ticket's ownership ticket was assigned
  • licenses - An array of integers containing the package IDs for all the licenses the ticket owner owns which grant them this app
  • dlc - An array of objects, each of which contains:
    • appID - The AppID of the piece of DLC
    • licenses - An array of integers containing the package IDs for all the licenses the ticket owner owns which grant them this DLC. Seems to not work right now.
  • userData - Whatever data was sent by the user to Steam when they requested the ticket

Returns null if the provided ticket could not be parsed or could not be verified for authenticity. If you get data returned, it is guaranteed that it has not been tampered with, provided your encryption key has not been compromised.

To determine if a ticket is valid, you should do the following:

  1. Check that the AppID matches the AppID you expect
  2. If the user has already supplied their SteamID, make sure it matches the one in the ticket
  3. Make sure it hasn't been generated too far in the past for your liking
  4. If you built a nonce into the ticket, make sure the userData matches what you expect

If you want to have a relatively long grace period in which an encrypted app ticket can be used, but you also want to make sure that it wasn't reused, you can send a nonce to the client and have them build that into their encrypted app ticket's userData.

Methods

getAuthSessionTicket(appid, callback)

  • appid - The ID of the app you want a ticket for
  • callback - A function to be called when the ticket is available
    • err - An Error object on failure, or null on success
    • ticket - A Buffer containing the requested appticket

The returned ticket contains everything you need and should be sent verbatim to your partner (i.e. a game server or P2P client).
Note that the ticket itself may not be usable if you aren't marked as in-game for the specified app on Steam.

Once you're done with the ticket, you should cancel it using cancelAuthTicket.

getAppOwnershipTicket(appid, callback)

  • appid - The ID of the app you want an ownership ticket for
  • callback - A function to be called when the ticket is available
    • err - An Error object on failure, or null on success
    • ticket - A Buffer containing the requested ownership ticket

Gets an app ownership ticket. You can't use this to authenticate with game servers, but you could use this to prove to someone that you own an app. Chances are, you don't want this. This is used internally by getAuthSessionTicket.

If you have local file storage enabled, this will save your ownership tickets to disk (unless you set the saveAppTickets steam-user option to false). If present and not expired, they will be supplied from disk whenever possible.

If you acquire some DLC between when a ticket is saved to disk and when you call this method, the ticket you get back might not contain information about that DLC.

Ownership tickets can be parsed with parseAppTicket but the result will be missing some properties that are contained in other ticket sections, since ownership tickets aren't full app tickets.

cancelAuthTicket(appid, callback)

  • appid - The ID of the app you want to cancel your ticket(s) for
  • callback - Optional. Called when Steam acknowledges the canceling.
    • err - An Error object on failure, or null on success

Cancels all outstanding app tickets for the specified app (and perhaps for all games, that's untested).
You should call this when you're done with your auth session so someone can't steal your ticket.

This doesn't affect the app ownership ticket that was used in this app ticket. Ownership tickets cannot be canceled and only become invalidated when they expire.

Events

authTicketStatus

  • status - An object containing these properties:
    • steamID - A SteamID object containing the ticket owner's SteamID (always yours)
    • appOwnerSteamID - A SteamID object containing the app owner's SteamID (usually yours but might not be if you're using family sharing)
    • appID - The AppID of the app for which your ticket is being validated
    • ticketCrc - The CRC32 of the ticket in question
    • state - A value from some enum I'm not sure about right now
    • authSessionResponse - A value from the EAuthSessionResponse enum

Emitted when the status of your auth ticket changes, for example when it's validated by a server or peer.

Clone this wiki locally