-
Notifications
You must be signed in to change notification settings - Fork 494
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1129 from xPaw/authentication
Add `SteamAuthentication` to handle new Steam login flow sessions
- Loading branch information
Showing
17 changed files
with
1,146 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
using System; | ||
using System.Text.Json; | ||
using SteamKit2; | ||
using SteamKit2.Authentication; | ||
|
||
if ( args.Length < 2 ) | ||
{ | ||
Console.Error.WriteLine( "Sample1a: No username and password specified!" ); | ||
return; | ||
} | ||
|
||
// save our logon details | ||
var user = args[ 0 ]; | ||
var pass = args[ 1 ]; | ||
|
||
// create our steamclient instance | ||
var steamClient = new SteamClient(); | ||
// create the callback manager which will route callbacks to function calls | ||
var manager = new CallbackManager( steamClient ); | ||
|
||
// get the steamuser handler, which is used for logging on after successfully connecting | ||
var steamUser = steamClient.GetHandler<SteamUser>(); | ||
|
||
// register a few callbacks we're interested in | ||
// these are registered upon creation to a callback manager, which will then route the callbacks | ||
// to the functions specified | ||
manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected ); | ||
manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected ); | ||
|
||
manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn ); | ||
manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff ); | ||
|
||
var isRunning = true; | ||
|
||
Console.WriteLine( "Connecting to Steam..." ); | ||
|
||
// initiate the connection | ||
steamClient.Connect(); | ||
|
||
// create our callback handling loop | ||
while ( isRunning ) | ||
{ | ||
// in order for the callbacks to get routed, they need to be handled by the manager | ||
manager.RunWaitCallbacks( TimeSpan.FromSeconds( 1 ) ); | ||
} | ||
|
||
async void OnConnected( SteamClient.ConnectedCallback callback ) | ||
{ | ||
Console.WriteLine( "Connected to Steam! Logging in '{0}'...", user ); | ||
|
||
// Begin authenticating via credentials | ||
var authSession = await steamClient.Authentication.BeginAuthSessionViaCredentialsAsync( new AuthSessionDetails | ||
{ | ||
Username = user, | ||
Password = pass, | ||
IsPersistentSession = false, | ||
Authenticator = new UserConsoleAuthenticator(), | ||
} ); | ||
|
||
// Starting polling Steam for authentication response | ||
var pollResponse = await authSession.PollingWaitForResultAsync(); | ||
|
||
// Logon to Steam with the access token we have received | ||
// Note that we are using RefreshToken for logging on here | ||
steamUser.LogOn( new SteamUser.LogOnDetails | ||
{ | ||
Username = pollResponse.AccountName, | ||
AccessToken = pollResponse.RefreshToken, | ||
} ); | ||
|
||
// This is not required, but it is possible to parse the JWT access token to see the scope and expiration date. | ||
ParseJsonWebToken( pollResponse.AccessToken, nameof( pollResponse.AccessToken ) ); | ||
ParseJsonWebToken( pollResponse.RefreshToken, nameof( pollResponse.RefreshToken ) ); | ||
} | ||
|
||
void OnDisconnected( SteamClient.DisconnectedCallback callback ) | ||
{ | ||
Console.WriteLine( "Disconnected from Steam" ); | ||
|
||
isRunning = false; | ||
} | ||
|
||
void OnLoggedOn( SteamUser.LoggedOnCallback callback ) | ||
{ | ||
if ( callback.Result != EResult.OK ) | ||
{ | ||
Console.WriteLine( "Unable to logon to Steam: {0} / {1}", callback.Result, callback.ExtendedResult ); | ||
|
||
isRunning = false; | ||
return; | ||
} | ||
|
||
Console.WriteLine( "Successfully logged on!" ); | ||
|
||
// at this point, we'd be able to perform actions on Steam | ||
|
||
// for this sample we'll just log off | ||
steamUser.LogOff(); | ||
} | ||
|
||
void OnLoggedOff( SteamUser.LoggedOffCallback callback ) | ||
{ | ||
Console.WriteLine( "Logged off of Steam: {0}", callback.Result ); | ||
} | ||
|
||
|
||
|
||
// This is simply showing how to parse JWT, this is not required to login to Steam | ||
void ParseJsonWebToken( string token, string name ) | ||
{ | ||
// You can use a JWT library to do the parsing for you | ||
var tokenComponents = token.Split( '.' ); | ||
|
||
// Fix up base64url to normal base64 | ||
var base64 = tokenComponents[ 1 ].Replace( '-', '+' ).Replace( '_', '/' ); | ||
|
||
if ( base64.Length % 4 != 0 ) | ||
{ | ||
base64 += new string( '=', 4 - base64.Length % 4 ); | ||
} | ||
|
||
var payloadBytes = Convert.FromBase64String( base64 ); | ||
|
||
// Payload can be parsed as JSON, and then fields such expiration date, scope, etc can be accessed | ||
var payload = JsonDocument.Parse( payloadBytes ); | ||
|
||
// For brevity we will simply output formatted json to console | ||
var formatted = JsonSerializer.Serialize( payload, new JsonSerializerOptions | ||
{ | ||
WriteIndented = true, | ||
} ); | ||
Console.WriteLine( $"{name}: {formatted}" ); | ||
Console.WriteLine(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<Company>SteamRE</Company> | ||
<Product>Sample1a_Authentication</Product> | ||
<Authors /> | ||
<Description>SteamKit Sample 1a: Authentication</Description> | ||
<Copyright>Copyright © Pavel Djundik 2023</Copyright> | ||
<PackageId>Sample1a_Authentication</PackageId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\SteamKit2\SteamKit2\SteamKit2.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
using System; | ||
using QRCoder; | ||
using SteamKit2; | ||
using SteamKit2.Authentication; | ||
|
||
// create our steamclient instance | ||
var steamClient = new SteamClient(); | ||
// create the callback manager which will route callbacks to function calls | ||
var manager = new CallbackManager( steamClient ); | ||
|
||
// get the steamuser handler, which is used for logging on after successfully connecting | ||
var steamUser = steamClient.GetHandler<SteamUser>(); | ||
|
||
// register a few callbacks we're interested in | ||
// these are registered upon creation to a callback manager, which will then route the callbacks | ||
// to the functions specified | ||
manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected ); | ||
manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected ); | ||
|
||
manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn ); | ||
manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff ); | ||
|
||
var isRunning = true; | ||
|
||
Console.WriteLine( "Connecting to Steam..." ); | ||
|
||
// initiate the connection | ||
steamClient.Connect(); | ||
|
||
// create our callback handling loop | ||
while ( isRunning ) | ||
{ | ||
// in order for the callbacks to get routed, they need to be handled by the manager | ||
manager.RunWaitCallbacks( TimeSpan.FromSeconds( 1 ) ); | ||
} | ||
|
||
async void OnConnected( SteamClient.ConnectedCallback callback ) | ||
{ | ||
// Start an authentication session by requesting a link | ||
var authSession = await steamClient.Authentication.BeginAuthSessionViaQRAsync( new AuthSessionDetails() ); | ||
|
||
// Steam will periodically refresh the challenge url, this callback allows you to draw a new qr code | ||
authSession.ChallengeURLChanged = () => | ||
{ | ||
Console.WriteLine(); | ||
Console.WriteLine( "Steam has refreshed the challenge url" ); | ||
|
||
DrawQRCode( authSession ); | ||
}; | ||
|
||
// Draw current qr right away | ||
DrawQRCode( authSession ); | ||
|
||
// Starting polling Steam for authentication response | ||
// This response is later used to logon to Steam after connecting | ||
var pollResponse = await authSession.PollingWaitForResultAsync(); | ||
|
||
Console.WriteLine( $"Logging in as '{pollResponse.AccountName}'..." ); | ||
|
||
// Logon to Steam with the access token we have received | ||
steamUser.LogOn( new SteamUser.LogOnDetails | ||
{ | ||
Username = pollResponse.AccountName, | ||
AccessToken = pollResponse.RefreshToken, | ||
} ); | ||
} | ||
|
||
void OnDisconnected( SteamClient.DisconnectedCallback callback ) | ||
{ | ||
Console.WriteLine( "Disconnected from Steam" ); | ||
|
||
isRunning = false; | ||
} | ||
|
||
void OnLoggedOn( SteamUser.LoggedOnCallback callback ) | ||
{ | ||
if ( callback.Result != EResult.OK ) | ||
{ | ||
Console.WriteLine( "Unable to logon to Steam: {0} / {1}", callback.Result, callback.ExtendedResult ); | ||
|
||
isRunning = false; | ||
return; | ||
} | ||
|
||
Console.WriteLine( "Successfully logged on!" ); | ||
|
||
// at this point, we'd be able to perform actions on Steam | ||
|
||
// for this sample we'll just log off | ||
steamUser.LogOff(); | ||
} | ||
|
||
void OnLoggedOff( SteamUser.LoggedOffCallback callback ) | ||
{ | ||
Console.WriteLine( "Logged off of Steam: {0}", callback.Result ); | ||
} | ||
|
||
void DrawQRCode( QrAuthSession authSession ) | ||
{ | ||
Console.WriteLine( $"Challenge URL: {authSession.ChallengeURL}" ); | ||
Console.WriteLine(); | ||
|
||
// Encode the link as a QR code | ||
var qrGenerator = new QRCodeGenerator(); | ||
var qrCodeData = qrGenerator.CreateQrCode( authSession.ChallengeURL, QRCodeGenerator.ECCLevel.L ); | ||
var qrCode = new AsciiQRCode( qrCodeData ); | ||
var qrCodeAsAsciiArt = qrCode.GetGraphic( 1, drawQuietZones: false ); | ||
|
||
Console.WriteLine( "Use the Steam Mobile App to sign in via QR code:" ); | ||
Console.WriteLine( qrCodeAsAsciiArt ); | ||
} |
22 changes: 22 additions & 0 deletions
22
Samples/1b.QrCodeAuthentication/Sample1b_QrCodeAuthentication.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<Company>SteamRE</Company> | ||
<Product>Sample1b_QrCodeAuthentication</Product> | ||
<Authors /> | ||
<Description>SteamKit Sample 1b: Authentication using QR codes</Description> | ||
<Copyright>Copyright © Pavel Djundik 2023</Copyright> | ||
<PackageId>Sample1b_QrCodeAuthentication</PackageId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="QRCoder" Version="1.4.3" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\SteamKit2\SteamKit2\SteamKit2.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.