Skip to content

Instantly share code, notes, and snippets.

@Ehesp
Last active May 17, 2024 04:21
Show Gist options
  • Save Ehesp/8315084 to your computer and use it in GitHub Desktop.
Save Ehesp/8315084 to your computer and use it in GitHub Desktop.
PHP Steam Login Script
<?php
/**
*
* Origin: http://forums.steampowered.com/forums/showthread.php?t=1430511
*
* @package Steam Community API
* @copyright (c) 2010 ichimonai.com
* @license http://opensource.org/licenses/mit-license.php The MIT License
*
*/
class SteamLogin
{
const STEAM_LOGIN = 'https://steamcommunity.com/openid/login';
/**
* Get the URL to sign into steam
*
* @param mixed returnTo URI to tell steam where to return, MUST BE THE FULL URI WITH THE PROTOCOL
* @param bool useAmp Use &amp; in the URL, true; or just &, false.
* @return string The string to go in the URL
*/
public static function genUrl($returnTo = false, $useAmp = true)
{
$returnTo = (!$returnTo) ? (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] : $returnTo;
$params = array(
'openid.ns' => 'http://specs.openid.net/auth/2.0',
'openid.mode' => 'checkid_setup',
'openid.return_to' => $returnTo,
'openid.realm' => (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'],
'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select',
'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select',
);
$sep = ($useAmp) ? '&amp;' : '&';
return self::STEAM_LOGIN . '?' . http_build_query($params, '', $sep);
}
/**
* Validate the incoming data
*
* @return string Returns the SteamID64 if successful or empty string on failure
*/
public static function validate()
{
// Star off with some basic params
$params = array(
'openid.assoc_handle' => $_GET['openid_assoc_handle'],
'openid.signed' => $_GET['openid_signed'],
'openid.sig' => $_GET['openid_sig'],
'openid.ns' => 'http://specs.openid.net/auth/2.0',
);
// Get all the params that were sent back and resend them for validation
$signed = explode(',', $_GET['openid_signed']);
foreach($signed as $item)
{
$val = $_GET['openid_' . str_replace('.', '_', $item)];
$params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($val) : $val;
}
// Finally, add the all important mode.
$params['openid.mode'] = 'check_authentication';
// Stored to send a Content-Length header
$data = http_build_query($params);
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' =>
"Accept-language: en\r\n".
"Content-type: application/x-www-form-urlencoded\r\n" .
"Content-Length: " . strlen($data) . "\r\n",
'content' => $data,
),
));
$result = file_get_contents(self::STEAM_LOGIN, false, $context);
// Validate wheather it's true and if we have a good ID
preg_match("#^http://steamcommunity.com/openid/id/([0-9]{17,25})#", $_GET['openid_claimed_id'], $matches);
$steamID64 = is_numeric($matches[1]) ? $matches[1] : 0;
// Return our final value
return preg_match("#is_valid\s*:\s*true#i", $result) == 1 ? $steamID64 : '';
}
}

This is a proof of concept to get you started. See this comment to ensure you address app security when using in production.

This script can be used standalone, with no other external libraries. The purpose is to send the user to the Steam login page, allow them to login, and handle the response back from Steam to gather their Community ID which can then be used in your application.

How to Use

Include File

In order to use this class, please ensure it is being loaded into your script/framework. For example include 'SteamLogin.php';

If needed, add a namespace to the file, example: <?php namespace Acme\Steam;.

Usage

The class has two static methods; genUrl and validate.

genUrl

This method creates a URL which points to Steam, esentially mimicing an OpenId request which the Steam API is able to handle. For more information on this, visit https://steamcommunity.com/dev

The method accepts two parameters;

  1. A URL which Steam will return to once the user has logged in. If no URL is provided, the script defaults to the current URL path.
  2. A boolen value of whether the & symbol should be converted to &amp in the URL created. This is true by default.

Usage:

Default URL: SteamLogin::genUrl(); Specific Return Location: SteamLogin::genUrl('http://mywebsite.com/login/response');

The response of this would sit inside of an anchor tag. Very basic example:

  <?php
    $url = SteamLogin::genUrl('http://mywebsite.com/login/response');
  ?>

  <a href="<?php echo $url; ?>">Login with Steam</a>
validate

This method parses the URL GET parameters which were passed back from Steam, thus it should sit wherever the returnTo location of your generated URL pointed to.

The return value of this method is either empty (string(0) '') or the logged in users Steam Community Id. If the response is empty, we can assume the login URL they tried to access has expired.

$response = SteamLogin::validate();

if( empty( $response ) ) {
  
  return 'The Steam Login request has now expired, please try again.';
  
}
else {
  
  return $response; // Community ID
  
}

Other helpful stuff

I'd reccommend using Steam Condenser to query the Steam servers to get more information about your logged in user. The library can be located at https://github.com/koraktor/steam-condenser

@Ehesp
Copy link
Author

Ehesp commented Aug 21, 2019

Cool - added a note at the top 👍

@ApertureDevelopment
Copy link

I don't really see the issue here, and the provided solution also doesnt really makes sense in this context.

In our case the server sets the return to url parameter and the openid provider returns the client to said url. I don't see how checking the return to parameter if its set correctly helps with anything really. In the case of SSL encryption, only 3 people know the url parameters, the client to be authenticated, my server and steam. For anyone else they would have to decrypt the data first, which is very unlikely.

The only way this: https://en.wikipedia.org/wiki/Replay_attack can really be a issue is in three cases

  1. The user has malicious software on his PC
  2. The server has malicious software reading the php variables
  3. The connection between steam and the server is not encrypted

So can you please explain me what I am not seeing here?

@kbkk
Copy link

kbkk commented Jul 25, 2020

@ApertureDevelopment

This is the case where one of the sites you sign in with steam has malicious owners (attackers).
Once you sign in with steam, they can use your token on vulnerable sites.

@ApertureDevelopment
Copy link

Oh, now I get it. So in the callback, you verify that the returnto is valid, because if you upstream check it with steam with a different returnto it would not be valid, but when I send steam the same returnto paramater it replies that the data is valid. So you check if the returnto is the same as your servers configuration, otherwise someone is trying to use someone elses authentication callback, right?

@kbkk
Copy link

kbkk commented Jul 25, 2020

Yes, exactly.

@Null8585
Copy link

Null8585 commented Sep 8, 2021

کار نمیکند

no is working

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment