Skip to content
Giorgio edited this page Nov 13, 2021 · 6 revisions

Riot Games use an XMPP server with a custom authentication mechanism to broadcast the presence of all their games.

Prerequisites

To authenticate with the XMPP server, you will need two tokens, an RSO token and a PAS token.

RSO

The methods of obtaining an RSO token are documented here.

The plugin uses GET Cookie Reauth which lets it get a new token using the player's cookies. This avoids the hassle of two-factor authentication and google sign in, while also allowing us not store the user's password in plain text.

PAS

The PAS token can be obtained from the following endpoint:

GET https://riot-geo.pas.si.riotgames.com/pas/v1/service/chat
Headers:
 Authorization: Bearer <RSO token>

Getting the XMPP server's address

The address of the XMPP server depends on the region of the account. To get the region code for your account, decode your PAS token and get the affinity.

To get the list of XMPP servers, use the clientconfig endpoint:

GET https://clientconfig.rpg.riotgames.com/api/v1/config/player?os=windows&region=EUW&app=Riot%20Client&version=39.0.0.3949982&patchline=KeystoneFoundationLiveWin
Headers:
 x-riot-entitlements-jwt: <entitlements token>
 authorization: Bearer <RSO token>

You will need to get an entitlements token.

The XMPP server addresses are unlikely to change, which is why I hardcoded them in my plugin.

Connecting to the XMPP server

The connection happens using a TCP stream encrypted using TLS over port 5223.

Once connected, send these messages one by one, waiting for riot servers to respond between each one:

<?xml version="1.0"?><stream:stream to="${XMPPRegion}.pvp.net" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<auth mechanism="X-Riot-RSO-PAS" xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><rso_token>${RSO}</rso_token><pas_token>${PAS}</pas_token></auth>
<?xml version="1.0"?><stream:stream to="${XMPPRegion}.pvp.net" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<iq id="_xmpp_bind1" type="set"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"></bind></iq>
<iq id="_xmpp_session1" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>

Make sure to replace ${RSO} and ${PAS} with your tokens, and ${XMPPRegion} with your XMPP region.
Note your XMPP region is not the same as your account region, although the map of "account regions -> XMPP regions" is obtained using the clientconfig endpoint described above.

Once you send these messages, you should be authenticated and ready to ask for the friends list and presences.

NOTE: Riot likes to split up large messages into two or more chunks somewhat arbitrarily. Make sure you have got the complete XML message before you start processing it.

Getting the friends list

To ask for the friends list, send the following:

<iq type="get" id="2"><query xmlns="jabber:iq:riotgames:roster" last_state="true" /></iq>

Getting your friend's presences

Once you send any presence, you are asking for the list of friend presences as well as asking to receive all future presence updates. Simply sending <presence/> is enough.

You can also use this to spoof your presence to your friends.

Presence format

Here is what a Valorant presence should look like:

<presence from='[email protected]/RC-123456789' to='[email protected]/987654321' id='presence_69'>
    <games>
        <keystone>
            <st>chat</st>
            <s.t>1611172871420</s.t>
            <m>custom status go brrrr</m>
            <s.p>keystone</s.p>
        </keystone>
        <valorant>
            <st>chat</st>
            <s.t>1611172871069</s.t>
            <s.d/>
            <s.l/>
            <m/>
            <s.a/>
            <p>ewoJImlzVmFsaWQiOiBmYWxzZSwKCSJ3aGF0IjogInRoaXMgaXMganVzdCBzYW1wbGUgZGF0YSBkdWRlIDopIiwKfQ==</p>
            <s.p>valorant</s.p>
        </valorant>
    </games>
    <show>chat</show>
    <status/>
</presence>

There are two "games" being played, keystone and valorant. Keystone is simply the fact that the user is able to receive chat messages, so it can be ignored.

<s.t> contains the timestamp the presence was last updated. If a Riot client or game receives multiple presences for the same game, it displays the one with the most recent timestamp.

Note: If a friend has downloaded the "Riot Mobile" app (formerly League+), they will always return a keystone presence regardless of whether they are online or not.

To get started with the format of Valorant presences, check out the bottom of this page.

Acknowledgements

  • molenzwiebel's Deceive source code, which helped me tremendously in figuring out Riot's XMPP, and even how XMPP works in the first place. That man is either a genius, or works for Riot Games
  • The Valorant App Developers Discord Server, with a special thanks to Hamper and his vast knowledge of everything Valorant and helping me get the plugin to a usable state
  • techchrism's Valorant API Docs on how Riot's auth works
Clone this wiki locally