Lo primero que haría cualquiera en su sano juicio cuando va a realizar por vez primera el proceso de autenticar a un usuario usando GitHub, es investigar en Internet cómo hacerlo, al menos eso hice yo y curiosamente, entender el proceso no fue tan fácil y/o inmediato como imaginé que sería. Siendo PHP mi herramienta de programación predilecta, encontré páginas donde te explicaban qué necesitabas, otras donde relegaban todo el proceso en módulos de terceros o ya incluidos en frameworks como Laravel y unas pocas donde te entregaban bloques de código para hacerlo pero no te explicaban el “paso a paso” del proceso para poder entenderlo claramente antes de pasar a los detalles del código.
Habiendo resuelto el acertijo no tan complicado de ese “cómo hacerlo”, permíteme compartirlo contigo, para que puedas también usarlo sin problema.
(Aviso: Este artículo fue originalmente publicado en Medium.com).
En pocas palabras
El proceso de autenticación sigue la siguiente secuencia:
- Se solicita a GitHub que realice la autenticación, redirigiendo la página de tu aplicación a una página en GitHub.
- GitHub realiza todo el proceso de verificación del usuario, esto es, solicitar credenciales si el usuario no ha iniciado sesión o validando la sesión actual en caso que se tenga una activa.
- GitHub redirige el resultado a una página en tu aplicación (previamente configurada en los servicios de GitHub) con una llave o token de uso temporal, para que con él solicites un nuevo código de acceso, que será el que usarás en posteriores consultas de la API de GitHub si lo requieres.
- A partir de ese punto, tu aplicación deberá dar el debido manejo de sesión con el usuario autenticado vía GitHub.
Repasemos cada uno de estos pasos con un poco más de detalle.
Solicitando la autenticación a GitHub
Todo comienza con una consulta a GitHub para que solicite al usuario sus credenciales de autenticación. Durante este paso, toda la información a intercambiar entre el sitio Web de tu aplicación y GitHub será pública, realizada por medio de URLs desde el navegador Web, tanto la petición como la respuesta.
La estructura de la URL a redirigir es la siguiente:
https://github.com/login/oauth/authorize? client_id=[GitHub client ID]& redirect_uri=[Authorization callback URL]& state=[Cadena de validación]& scope=[Permisos solicitados a GitHub]
En PHP podemos construir esta URL con una sentencia del tipo:
$url = 'https://github.com/login/oauth/authorize?' .
http_build_query([
'client_id' => $client_id,
'redirect_uri' => $redirect_uri,
'state' => $state,
'scope' => $scope
]);
¿A qué corresponde cada uno de estos elementos?
En la primera parte de este artículo, vimos como configurar en nuestra cuenta de GitHub una “aplicación” autorizada para proveer el servicio de autenticación/autorización de usuarios. Una vez hecho eso, tenemos disponibles los siguientes datos:
- Cliente ID o llave pública de cliente, que para efectos de este artículo asignaremos a una variable llamada $client_id.
- Client secret o llave privada de cliente, a usar más adelante en una variable $client_secret.
- Authorization callback URL. Este valor es de carácter obligatorio y corresponde a la URL donde GitHub retornará los valores de autenticación. Es el valor a usar en la variable $redirect_uri.
El valor asignado a $state es el de una cadena alfanumérica que creamos en nuestra aplicación y que será usada para validar que la respuesta que se reciba de GitHub sea efectivamente a nuestra petición de autenticación. Se recomienda por tanto que sea única para cada consulta y que sea almacenada internamente para contrastar con la respuesta. Por ejemplo:
session_start(); $_SESSION['state'] = base64_encode(random_bytes(48)); $state = $_SESSION['state'];
Finalmente, el valor de $scope refiere a los permisos requeridos para la interacción de nuestra aplicación Web con GitHub, permisos que deben ser validados por el usuario que se autentica y que como usuarios, no debemos tomar a la ligera al autenticarnos. Algunos de los permisos que tradicionalmente se solicitan son:
- read:user. Acceso de sólo lectura a la información de usuario
- user:email. Correo electrónico del usuario. ¿Por qué solicitar explícitamente el correo incluso si ya se ha solicitado la información del usuario? Esto se debe a que si el usuario ha marcado su correo primario como “privado”, GitHub lo oculta en los datos generales de usuario pero lo provee (junto con cualquier otro correo adicional provisto por el usuario) si se solicita explícitamente con este permiso.
- repo. Acceso a los repositorios del usuario, del que hablaremos en un momento.
Estos alcances pueden indicarse así:
$scope = 'read:user,user:email,repo';
Importante aclaración sobre el permiso “repo”: Se debe tener mucho cuidado con este permiso ya que (por razones desconocidas) GitHub no permite otorgar permisos de sólo lectura a los repositorios, sino que siempre da acceso total a ellos, de forma que desde la aplicación Web autorizada pueden leerse y modificarse dichos repositorios, así que si este permiso es solicitado, asegúrate de conocer con claridad el uso que la aplicación que los solicita dará a ellos. Como usuarios de GitHub, debemos tener mucho cuidado al dar esta clase de permisos a aplicaciones Web de terceros y como creadores de aplicaciones, debemos tener presente solicitar solamente los permisos que realmente se necesiten para no incomodar a los usuarios durante el proceso de autenticación.
Cuando se carga la URL en el navegador, vemos que corresponde a una página propietaria de GitHub donde solicita el usuario y contraseña. Posteriormente (si las credenciales son correctas) se notifica al usuario sobre los permisos requeridos por la aplicación Web solicitante sobre su cuenta, para que así los autorice o niegue.
Téngase presente que si no se indican valores para el “scope” o alcance deseado, GitHub dará acceso de solo lectura a la información pública del usuario, tanto de su perfil como de sus repositorios. En este caso no podrán consultarse los repositorios que el usuario haya registrado como “privados” ni a la información del correo electrónico cuando sea de carácter privado.
Para más información sobre los permisos que pueden darse usando el atributo “scope”, puedes consultar las ayudas de GitHub sobre este tema.
Una vez que el usuario autoriza o niega los permisos de uso, GitHub redirecciona el navegador al sitio web indicado por el valor $redirect_uri e incluye en la URL diferentes valores de respuesta, dependiendo de si el proceso de autenticación fue fallido o exitoso.
Es importante resaltar que si el valor de la URL de retorno (indicado por el elemento “redirect_uri” en la URL de consulta) es diferente al registrado en la aplicación de GitHub (Authorization callback URL), el proceso de autenticación será interrumpido.
Para mayor información y detalles sobre el proceso de autenticación en GitHub, puedes consultar la página de GitHub sobre Autorizaciones Oauth.
Autenticación fallida
Cuando la autenticación es fallida o el usuario decide no aprobarla, se redirecciona el navegador a la URL de retorno con los siguientes argumentos:
http://your-application-redirect-uri? error=[Code]& error_description=[Mensaje descriptivo]& error_uri=[Enlace con información del error]& state=[Cadena de validación]
Es importante usar siempre el valor de “state” retornado para confirmar que realmente corresponde a la respuesta de la petición enviada y prevenir suplantaciones.
Los valores de “error” y “error_description” (usualmente en inglés) darán detalles del error ocurrido. El enlace recibido en “error_uri” suele complementar la descripción pero muchas veces relaciona solo una página de información genérica en GitHub.
No es mucho más lo que se puede decir en este apartado, pero puedes explorar algunos posibles códigos de error reportados en la página de GitHub sobre errores de autorización.
Autenticación exitosa
Cuando la autenticación es exitosa, se redirecciona el navegador a la URL de retorno con los siguientes argumentos:
http://your-application-redirect-uri? code=[Código temporal de acceso]& state=[Cadena de validación]
De nuevo insisto, se debe usar “state” para validar la respuesta y confirmar que realmente corresponde a la petición enviada. Esto debe hacerse antes de procesar la respuesta recibida, cualquiera sea, lo que en PHP equivale a incluir una línea de código como la siguiente:
if (isset($_GET['state']) && trim($_GET['state']) === $_SESSION['state']) {
// Procede a procesar la respuesta recibida
...
}
Esa caja de herramientas mágica llamada cURL
Los pasos siguientes en este proceso de autenticación se realizan en el back-end de la aplicación Web, de forma que la comunicación con GitHub ocurre “tras bambalinas”, oculta a ojos de “usuarios malintencionados”, porque es aquí que se realiza el intercambio de claves que son de carácter “secreto” y que deben por definición estar protegidas del público. Para realizar esta comunicación, GitHub provee diferentes endpoints, URLs que proveen servicios y a los que podemos acceder desde PHP usando la librería cURL. Así que antes de continuar, definamos una función que pueda proveer las diferentes funcionalidades que habremos de necesitar.
function github_request(
string $url,
mixed $parameters = '',
array $headers = [],
string $basic_auth = ''
)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
// Valida si envía parámetros via POST y les da formato
$args = '';
if (is_array($parameters) && count($parameters) > 0) {
// Recibe arreglo de datos, convierte a formato URL
$args = http_build_query($parameters);
} elseif (is_string($parameters) && $parameters !== '') {
// Recibe texto directamente
$args = trim($parameters);
}
if ($args !== '') {
curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
}
// Headers requeridos para la solicitud a GitHub
$headers[] = 'Accept: application/json';
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
$headers[] = 'User-Agent: MiFrame-Tools/CurlManager';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if ($basic_auth !== '') {
curl_setopt($ch, CURLOPT_USERPWD, $basic_auth);
}
// Get the response from the access token request
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
// Valida si la respuesta fue exitosa
if ($info['http_code'] == 200) {
$json = json_decode($response, true);
// Close the cURL session
curl_close($ch);
if (is_array($json)) {
return $json;
}
}
// Solicitud fallida
return false;
}
Tip: El header “User-Agent” es exigido por las APIs de GitHub, así que recuerda incluirlo siempre, independiente del mecanismo de consulta que utilices, sea cURL y otro de tu preferencia.
Solicitando el código de autorización
En toda respuesta exitosa se recibe un elemento “code” que corresponde a un código temporal que tiene una duración aproximada de 10 minutos y que debe usarse para recuperar uno de carácter más duradero, que será el código de acceso o token que usaremos como autorización en todas las consultas siguientes que se realicen a la API de GitHub. Para recuperar este token, realizamos la siguiente consulta:
$parameters = [
'client_id' => $client_id,
'client_secret' => $client_secret,
'code' => $_GET['code'],
'redirect_uri' => $redirect_uri,
];
$response = github_request(
'https://github.com/login/oauth/access_token',
$parameters
);
if ($response !== false) {
$access_token = $response['access_token'];
}
Los valores de $client_id, $client_secret y $redirect_uri son los que se obtuvieron del registro de nuestra aplicación Web en GitHub. La respuesta a esta consulta (cuando es exitosa) es un arreglo con los siguientes valores:
Array
(
[access_token] => xxx,
[scope] => xyz,
[token_type] => bearer
)
En algunos escenarios, puede ser relevante validar el “scope” retornado, que corresponde al alcance autorizado por el usuario, para así evitar realizar consultas a GitHub que puedan resultar fallidas por no contar con el permiso necesario.
Recuperando datos del usuario
Para recuperar la información del usuario, realizamos la siguiente consulta:
$auth_header = [ "Authorization: Bearer {$access_token}" ];
$response = github_request(
'https://api.github.com/user',
headers: $auth_header
);
El valor de $access_token es usado para notificar a GitHub que la consulta es de un usuario previamente autenticado y autorizado. En respuesta, se recibe un arreglo con una distribución similar a la siguiente:
Array
(
[login] => xxx
[id] => xyz
[avatar_url] => https://avatars.githubusercontent.com/u/...
[gravatar_id] =>
[url] => https://api.github.com/users/...
[html_url] => https://github.com/...
[name] => John Doe
[email] =>
[created_at] => 2018-10-01T19:23:18Z
[updated_at] => 2024-03-27T11:28:44Z
...
)
Como se mencionó arriba, si el correo es privado no será incluido en los datos del usuario. Para obtener correctamente los correos electrónicos registrados y siempre que haya incluido “user:email” en el “scope” del registro, puede realizar la siguiente consulta:
$response = github_request(
'https://api.github.com/user/emails',
headers: $auth_header
);
En respuesta a esta consulta, se obtiene una respuesta arreglo del tipo:
Array
(
[0] => Array
(
[email] => 'xyz@email.com',
[primary] => true,
[verified] => true,
[visibility] => 'private'
)
[1] => Array
(
[email] => 'axz@email.com',
[primary] => false,
[verified] => true,
[visibility] => ''
)
...
)
El correo principal del usuario será aquel marcado con “primary” en valor true. Puede también ser relevante validar que el correo haya sido verificado por GitHub (elemento “verified” en valor true).
Validación del token asignado
En nuestra aplicación Web podemos encontrarnos con alguno de estos escenarios:
- Se consulta un servicio que requiera de un token vigente y GitHub responde con un código de error 404 indicando que el token reportado ya no es valido , lo que puede ocurrir si ha superado su vigencia o si el usuario lo ha “eliminado” desde su cuenta en GitHub.
- Cuando GitHub se usa sólo como medio de autenticación, sin hacer uso de otros de sus servicios, se puede requerir validar la vigencia del usuario. Esto es especialmente cierto en aplicaciones que mantienen “la sesión abierta” durante tiempo indefinido.
En estos casos y algunos otros, es necesario validar periódicamente que el token siga activo. Esto se consigue con una consulta a la API de GitHub que emplea autenticación básica usando $client_id como username y $client_secret como password, a saber:
$basic_auth = "{$client_id}:{$client_secret}";
$response = github_request(
"https://api.github.com/applications/{$client_id}/token",
json_encode(['access_token' => $access_token]),
basic_auth: $basic_auth
);
Si el token no es valido, la consulta retorna un código de error. Por el contrario, si el token está vigente, retorna un arreglo con los siguientes datos:
Array
(
[id] => xxxx
[url] => https://api.github.com/authorizations/...
[token] => xyz
[created_at] => 2025-04-29T20:14:55Z
[updated_at] => 2025-04-29T20:14:55Z
...
)
Información adicional sobre este proceso puede verse en la página de GitHub sobre chequeo de tokens.
Restricciones
Por supuesto, no todo es “color de rosas” como dicen. Hay varias limitaciones a considerar cuando se realizan autenticaciones a través de GitHub:
- Se tiene un límite de 10 tokens a asignar por usuario/aplicacion/scope, es decir, para un mismo usuario con la misma aplicación y el mismo alcance, se pueden crear hasta 10 tokens si se requiere.
- Se tiene un tope de máximo 10 tokens a crear por hora.
- Si el token es almacenado en un repositorio público de GitHub (algo que no se debería hacer, incluso en repositorios privados), será automáticamente suspendido por GitHub.
- Para usuarios autenticados, GitHub permite realizar hasta 5.000 consultas por hora a sus APIs (estas consultas aplican para solicitudes de autorización, datos de usuario y correos, información de los repositorios, etc.). Usuarios no autenticados pueden realizar hasta 60 consultas por hora. Para cuentas corporativas, este límite es de 15.000 consultas por hora.
Vale resaltar que la consulta de validación de tokens descrita en la sección anterior (y que emplea autorización básica) no se contabiliza como parte de las consultas por hora permitidas.
Para terminar…
Usar GitHub como medio para autenticar a tus usuarios puede ser una alternativa para aplicaciones que estén dirigidas a estudiantes o profesionales del desarrollo de software, que son los que usualmente tienen cuentas allí creadas. En ese contexto, espero que este artículo pueda servirte de guía para implementar tu propio esquema de autenticación usando GitHub.
Antes de irte, comparte tus inquietudes y sugerencias en la sección de Comentarios.
¡Te espero en un próximo artículo!
Imagen modificada sobre un original de Mohamed Hassan tomada de Pixabay




Comentarios
Publicar un comentario