Back to Software

QR code login sharing

17 Feb 2011
Progress: Complete

This was based on a proposed idea by idris83. A feature many sites, such as facebook, would benefit from. I whipped up this little prototype when I read the idea.

Unlike the original idea though, this version does not need any special app installed. All you need is a phone with a web browser and a QR code reader.

As most people stay logged in to their social networking sites anyway, first visit the page below on your phone and hit log in via username. Choose anything.

Next visit the page on a public computer (or where ever you like). Hit log in via QR code, and scan it. This code contains a URL with a disposable session key which identifies the public computer. Since your phone has already been authenticated, when it visits the site with the new session, the site can simply duplicate the log in details into the public computer's session.

The test program is here.

Aside from making this very quickly one afternoon so there are inevitably bugs and security flaws (and the database is just a plain text file), the principle itself doesn't have any security holes if it were implemented properly.

The principle of what's going on is outlined in this schematic.

Phone logs in (and stays logged in) to website in the normal way.


Public computer accesses website and is assigned a session key, and an authorizing key.


Public computer displays authorizing key as QR code, and polls the site with its session key.


Phone reads QR code and visits the site with the authorizing key, and its login details.


The server now has everything it needs to assign the login details to the public computer's session.

By remembering the session association on the server, the phone could be used to log out of the public computer remotely too.

For the simplicity of this prototype both keys are the same, since I wasn't worried about security for this proof of concept.

Here's the source code for the sake of it.

<?php //A secure database would be used. $db="database.txt"; if ($_GET['ns'] and $_COOKIE['LogIn']) { $fh=fopen($db,'a'); fwrite($fh,"{$_GET['ns']}>{$_COOKIE['LogIn']}\n"); fclose($fh); die("Success - check your other computer."); } if ($_GET['check']) { if (file_exists($db)) $sessions=file($db); else die(); foreach ($sessions as $k => $value) { $d=explode(">",$value); if ($d[0]==$_GET['check']) { setcookie('LogIn',$d[1],time()+24*60*60); //Delete the disposable key unset($sessions[$k]); $fh=fopen($db,"w"); foreach($sessions as $value) fwrite($fh,$value); fclose($fh); die("Success"); } } die(); } switch ($_GET['action']) { case "login": if ($_POST['username']) { setcookie('LogIn',htmlentities($_POST['username']),time()+24*60*60); die("<script>window.location='?action='</script>"); } else echo "<form method='post'>Enter username:<input type='text' name='username'><input type='submit' value='Log in'></form>"; break; case "qrlogin": $key=md5(time()); //Don't care about security for the sake of this proof-of-concept echo "<body onload=\"ajax(page,'scriptoutput');\">"; google_qr($_SERVER['SCRIPT_URI']."?ns=".$key,200); ?><script type="text/javascript"> var page = "QRlogin.php?check=<?php echo $key; ?>"; function ajax(url,target) { // native XMLHttpRequest object //document.getElementById(target).innerHTML = 'Loading...'; if (window.XMLHttpRequest) { req = new XMLHttpRequest(); req.onreadystatechange = function() {ajaxDone(target);}; req.open("GET", url, true); req.send(null); // IE/Windows ActiveX version } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLDOM"); if (req) { req.onreadystatechange = function() {ajaxDone(target);}; req.open("GET", url, true); req.send(null); } } setTimeout("ajax(page,'scriptoutput')", 1000); } function ajaxDone(target) { // only if req is "loaded" if (req.readyState == 4) { // only if "OK" if (req.status == 200 || req.status == 304) { results = req.responseText; if (results=="Success") {window.location='?action=';} document.getElementById(target).innerHTML = results; } else { document.getElementById(target).innerHTML="ajax error:\n" + req.statusText; } } } </script> <div id='scriptoutput'></div> </body><? break; case "logout": setcookie('LogIn',"",-1); die("<script>window.location='?action='</script>"); default: if ($_COOKIE['LogIn']) echo"You are logged in as {$_COOKIE['LogIn']}. <br/><br/>Note the log-in cookie expires after a day - on your average social networking site, people usually tick 'keep me logged in'.<br/><br/><a href='?action=logout'>Log out</a>"; else echo "You are not logged in.<br/><br/><a href='?action=login'>Log in via user name</a><br/><br/><a href='?action=qrlogin'>Log in via QR code</a>"; } function google_qr($url,$size ='150',$EC_level='L',$margin='0'){ $url = urlencode($url); echo '<img src="http://chart.apis.google.com/chart?chs='.$size.'x'.$size.'&cht=qr&chld='.$EC_level.'|'.$margin.'&chl='.$url.'" alt="QR code" width="'.$size.'" height="'.$size.'"/>'; } ?>