Hoy veremos como hacer que los usuarios inicien sesión en nuestro sitio usando el API de Twitter. Esto tiene sentido si nuestro sitio planea hacer uso responsable del API y los accesos a la cuenta del usuario. Acá solo hablaré de como hacerlo a nivel general con PHP, sin usar un framework en particular, si ustedes usan otro lenguaje o herramientas, los principios son los mismos.

Primero veamos como funciona el proceso y luego lo pondremos en marcha. Para empezar necesitamos:

  • Tener una aplicación registrada en Twitter y saber los valores del consumer key y consumer secret. Es muy importante que estos valores no sean públicos, manténlos en secreto :)
  • Necesitamos una librería que se encargue de comunicarse al API usando OAuth, acá usaremos la de Abraham Williams

A grandes rasgos el proceso de autenticación vía Twitter es de la siguiente forma:

Autenticación vía Twitter

Nota: Los tokens no son otra cosa más que llaves usadas para identificar al usuario mientras se completa el proceso. Ahora veamos el proceso a detalle y con código.

Construir el URL de autenticación

Primero necesitamos una instancia de la clase TwitterOauth y con esta pediremos un identificador único al API, el mismo que nos servirá para tener una URL única hacia la que enviaremos al usuario. Digamos que esto solo se ejecuta cuando el usuario visita /login en nuestra app

// En alguna parte de app.php
//
if (  $request == '/login' ) {
	$url =  oauth_authlink( $config['oauth_callback'] );
	header('Location: ' . $url, true, 302);
	die;
}
// auth.php
//
function oauth_authlink( $callback = '' ) 
{
	include_once( 'twitterOAuth.php' );
	oauth = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET );
		
	oauth_clearcookies();
		
	/* Solicitar el token a twitter */
	$tok = $oauth->getRequestToken( $callback );
		
	/* Dejar los tokens guardados al usuario para pasos después, son temporales */
	setcookie('oauth_request_token', $tok['oauth_token'], 0 );
	setcookie('oauth_request_token_secret', $tok['oauth_token_secret'] , 0 );
		
	/* Construir el url de autenticación */
	return $oauth->getAuthorizeURL($tok['oauth_token'],true);
}

  1. Solo cuando el usuario visita /login se genera la URL única de autenticación, esto nos evita estár llamando al API a cada instante. Notar que la ejecución termina al enviar la redirección con header()
  2. El valor de $callback en oauth_authlink() es por si usamos una URL a la cual Twitter deba enviar al usuario de regreso a nuestra aplicación (ver paso 3), diferente a la que fue indicada en el registro de dicha aplicación.
  3. Los primeros tokens de la petición se guardan en cookies, esto nos sirve para reconocer al usuario más tarde en el proceso; son temporales y luego los borramos con oauth_clearcookies()

Recepción de la autorización

Twitter muestra al usuario la página donde le informa que nuestra aplicación solicita acceso a su cuenta; si en caso aún no ha iniciado sesión con Twitter, antes le pide registrarse para luego autorizar la aplicación.

Autorizar aplicacion en twitter

Solo nos interesa cuando el usuario nos autoriza el acceso y Twitter lo manda de regreso a nuestra aplicación. Si quedamos perdidos entre las pestañas del navegador o no confía en nosotros, es otra historia que no sabremos. Si previamente el usuario ya autorizó nuestra aplicación, Twitter no le pedirá permiso de nuevo y automáticamente redirecciona hacia nosotros.

Twitter enviará a usuario a la URL que indicamos durante el registro de la aplicación en Callback URL, o bien si enviamos una con $callback (ver arriba). Asumamos que fue hacia /auth donde Twitter envía a los usuarios:

// En alguna parte de app.php
//
	if ( strpos( $request , '/auth')===0 ) {
		authenticate_user();
	}
// auth.php
//

function oauth_authenticate()
{
	$token = isset( $_GET['oauth_token'] ) ? $_GET['oauth_token'] : '';
	$oauth_verifier = isset( $_GET['oauth_verifier'] ) ? $_GET['oauth_verifier'] : null;
		
	if ( $token == '' || !isset($_COOKIE['oauth_request_token']) || !isset($_COOKIE['oauth_request_token_secret']) 
	|| $_COOKIE['oauth_request_token']=='' || $_COOKIE['oauth_request_token_secret']=='' 
	|| $token != $_COOKIE['oauth_request_token'] ) 
	{
		return false;
	}

	// Usamos los tokens temporales
	include_once( 'twitterOAuth.php' );
	$to = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_COOKIE['oauth_request_token'], $_COOKIE['oauth_request_token_secret']);

	/* Ahora solicitamos los tokens de acceso, que serán permanentes */
	$tok = $to->getAccessToken( $oauth_verifier );
	if ( $to->lastStatusCode() != 200 )
		return false;
		
	$token = (string) $tok['oauth_token'];
	$token_secret = (string) $tok['oauth_token_secret'];
	$userid = (int) $tok['user_id'];
	if ($userid == 0 || empty($token) || empty($token_secret) )
		return false;
			
	$info = array();
	$info['userid'] = $userid;
	$info['token'] = $token;
	$info['token_secret'] = $token_secret;
		
	return $info;
}

function authenticate_user() 
{	
	$info = oauth_authenticate();
	if ( $info == false || !is_array($info) ) 
	{
		die( 'Autenticación no completada, datos incorrectos' ); // ustedes deben usar algo más elegante que die()
	}

	global $db;
	$user = $db->get_user( $info['userid'] );
	if ( empty($user) )  // primera vez por acá
	{
		$user = $db->add_user_from_twitter($info['userid'], $info['token'], $info['token_secret'])
	} else 
	{ // solo actualizar los tokens de acceso
		$db->update_user_tokens($info['userid'], $info['token'], $info['token_secret']);
	}
	
	oauth_clearcookies();
	auth_create_cookie( $info['userid'] );
	
	global $config;
	header('Location: ' . $config['site_url'], true, 301);
	die;
}

¡Más código! Pero vamos por partes explicándolo:

  1. oauth_authenticate() es la función encargada de validar al usuario respecto al API.
  2. Twitter nos envía varios parametros, oauth_token nos sirve para saber que usuario estamos procesando, cuyo valor es el mismo que solicitamos en el paso 1. Como nosotros guardamos estos tokens temporales como cookies, también los recibimos con la petición, de allí que comparemos si $token != $_COOKIE['oauth_request_token']. Por otra parte Twitter también nos envía oauth_verifier si estamos usando un callback URL diferente, el cual debemos usarlo al solicitar los tokens de acceso.
  3. Bien podríamos guardar los tokens temporales en la base de datos, ya que oauth_token nos sirve para saber cual estamos trabajando. Por ahora cookies resulta más fácil de trabajar.
  4. authenticate_user() es la función que va comunicarse con el resto de su aplicación/framework, se supone que ustedes ya tienen todas las llamadas a las funciones $db->* (con el correspondiente nombre de función que ustedes usen).
  5. $db->add_user_from_twitter() agrega un nuevo usuario a su aplicación con los datos regresados por twitter, seguramente quieran llamar al API para tener el nombre real y el username en base al ID devuelto por twitter (ver $info['userid']). $db->update_user_tokens() solo actualiza los tokes de acceso, en caso de que sean diferentes desde la ultima autorización. De nuevo estas son funciones que ustedes las deben adaptar a su aplicación.
  6. auth_create_cookie() crea los cookies de autenticación para su aplicación, que son diferentes a las que usamos temporalmente para twitter. No hay necesidad de estar autenticando de ahora en adelante con el API. Esto es similar a cuando ya sabemos que el usuario y contraseña son correctos, creamos las cookies que usaremos para validar al usuario (sin que vuelva a darnos su usuario y contraseña).
  7. Verificado el usuario y creadas las cookies, regresamos al usuario a la portada de nuestro sitio (o donde corresponda en su sitio).

De acá en adelante ya solo tenemos que usar los tokens de acceso, para llamar al API a nombre del usuario. Se asume que estos son permanentes, hasta que el usuario revoque la autorización a su cuenta.

¿Qué pasa si solo queremos actuar a nombre del usuario, pero no usar Twitter como sistema de autenticación en nuestra aplicación/sitio? Solo tenemos que cambiar en oauth_authlink():

return $oauth->getAuthorizeURL($tok['oauth_token'],true);

por:

return $oauth->getAuthorizeURL($tok['oauth_token'],false);

Solo el último parámetro cambia, que es el que indica si es una URL de autenticación o autorización. El resto es lo mismo, guardamos los tokens de acceso y procedemos con el resto de llamadas al API que necesitemos.


Pueden descargar los archivos base de este ejemplo
para que lo adapten a su aplicación o empiecen a experimentar por su cuenta (también incluí varias funciones para crear y borrar las cookies con las cuales verificaran al usuario). ¿Lo quieren ver funcionando? Solo vayan a nuestra sección de descargas que usa este mismo código.