Skip to content

Instantly share code, notes, and snippets.

@Ehesp
Last active May 12, 2023 05:35
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • 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

@vanvanni
Copy link

This just sends me to steamcommunity after clicking the link.... No Login Windows shows up...

@cristal2431
Copy link

Any sample to convert validate function to use curl?

@schneidernicholas
Copy link

schneidernicholas commented Apr 16, 2018

Valve has removed support for validating via http://. Change line 85 from:

preg_match("#^http://steamcommunity.com/openid/id/([0-9]{17,25})#", $_GET['openid_claimed_id'], $matches);

to

preg_match("#^https://steamcommunity.com/openid/id/([0-9]{17,25})#", $_GET['openid_claimed_id'], $matches);

@Abrynos
Copy link

Abrynos commented May 25, 2018

not working

@antim0118
Copy link

Valve has removed support for validating via http://. Change line 85 from:

THANK YOU VERY MUCH

Copy link

ghost commented Nov 30, 2018

I'm trying use this script. I can just generate URL, but the webhook to validator isn't working.

@kbkk
Copy link

kbkk commented Feb 7, 2019

Please do not use this script. It's vulnerable to replay attacks.

@codepushr
Copy link

@kbkk Can you elaborate? How is it vulnerable and what has to be done to secure it?

@kbkk
Copy link

kbkk commented Aug 21, 2019

@codepushr Basically it's missing this kind of check: https://github.com/kbkk/php-steam-auth/blob/32eeb2ba45a4373eb80c160650956524875bbbbf/src/SteamOpenId.php#L79

Simple attack scenario:

  1. You sign in with steam to an evil site
  2. evil site now has your openid token
  3. owner of evil site can now use this token on any site that uses this script and pretend to be you

I was really worried to find this script copy-pasted in some shop solutions (all I found were fixed).

Sorry for not describing this in my earlier post!

@Ehesp
Copy link
Author

Ehesp commented Aug 21, 2019

I'll happily remove this or change it if required - it was written many many years ago so I'd assume there is better solutions available now anyway... Didn't realise anyone was using it 😆

@codepushr
Copy link

@kbkk Thanks. I will dig into it and extend it.
@Ehesp You don't need to remove it, you can also put a disclaimer that it's a proof of concept and needs security tightened.

Reason I'm saying this is, there are not many OpenID 2.0 implementations out there as the spec is outdated, so any help is appreciated for upcoming steam API devs.

@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