Uso de OAuth 2.0 para aplicaciones web del cliente

En este documento, se explica cómo implementar la autorización de OAuth 2.0 para acceder a la API de YouTube Data desde una aplicación web de JavaScript. OAuth 2.0 permite a los usuarios compartir datos específicos con una aplicación y, al mismo tiempo, mantener la privacidad de sus nombres de usuario, contraseñas y otra información. Por ejemplo, una aplicación puede usar OAuth 2.0 para obtener permiso para recuperar los datos de YouTube de un canal.

Este flujo de OAuth 2.0 se denomina flujo de concesión implícito. Está diseñado para aplicaciones que acceden a las APIs solo mientras el usuario está presente en la aplicación. Estas aplicaciones no pueden almacenar información confidencial.

En este flujo, tu app abre una URL de Google que usa parámetros de consulta para identificar tu app y el tipo de acceso a la API que esta requiere. Puedes abrir la URL en la ventana del navegador actual o en una ventana emergente. El usuario puede autenticarse con Google y otorgar los permisos solicitados. Luego, Google redirecciona al usuario a tu app. El redireccionamiento incluye un token de acceso, que tu app verifica y, luego, usa para realizar solicitudes a la API.

Biblioteca cliente de las APIs de Google y Servicios de identidad de Google

Si usas la biblioteca cliente de las APIs de Google para JavaScript para realizar llamadas autorizadas a Google, debes usar la biblioteca de JavaScript de Google Identity Services para controlar el flujo de OAuth 2.0. Consulta el modelo de token de Google Identity Services, que se basa en el flujo de otorgamiento implícito de OAuth 2.0.

Requisitos previos

Habilita las API para tu proyecto.

Cualquier aplicación que llame a las APIs de Google debe habilitarlas en API Console.

Para habilitar una API en tu proyecto, sigue estos pasos:

  1. Open the API Library en Google API Console.
  2. If prompted, select a project, or create a new one.
  3. Usa la página Biblioteca para buscar y habilitar la API de YouTube Data. Busca otras APIs que usará tu aplicación y habilítala.

Crea credenciales de autorización

Cualquier aplicación que use OAuth 2.0 para acceder a las APIs de Google debe tener credenciales de autorización que identifiquen la aplicación para el servidor OAuth 2.0 de Google. En los siguientes pasos, se explica cómo crear credenciales para tu proyecto. Luego, tus aplicaciones podrán usar las credenciales para acceder a las APIs que habilitaste para ese proyecto.

  1. Go to the Credentials page.
  2. Haz clic en Crear credenciales > ID de cliente de OAuth.
  3. Selecciona el tipo de aplicación Aplicación web.
  4. Completa el formulario. Las aplicaciones que usan JavaScript para realizar solicitudes autorizadas a la API de Google deben especificar los orígenes de JavaScript autorizados. Los orígenes identifican los dominios desde los que tu aplicación puede enviar solicitudes al servidor de OAuth 2.0. Estos orígenes deben cumplir con las reglas de validación de Google.

Identifica los permisos de acceso

Los alcances permiten que la aplicación solo solicite acceso a los recursos que necesita, al tiempo que permiten a los usuarios controlar el nivel de acceso que otorgan a tu aplicación. Por lo tanto, puede haber una relación inversa entre la cantidad de permisos solicitados y la probabilidad de obtener el consentimiento del usuario.

Antes de que comiences a implementar la autorización de OAuth 2.0, te recomendamos identificar los alcances para los que la aplicación necesitará permiso de acceso.

La versión 3 de la API de YouTube Data usa los siguientes permisos:

Permisos
https://www.googleapis.com/auth/youtubeAdministrar tu cuenta de YouTube
https://www.googleapis.com/auth/youtube.channel-memberships.creatorVer una lista de los miembros actuales y activos de su canal, su nivel actual y el momento en que se hicieron miembros
https://www.googleapis.com/auth/youtube.force-sslVea, edite y borre de forma permanente sus videos, calificaciones, comentarios y subtítulos de YouTube
https://www.googleapis.com/auth/youtube.readonlyPermite ver tu cuenta de YouTube.
https://www.googleapis.com/auth/youtube.uploadPermite administrar tus videos de YouTube.
https://www.googleapis.com/auth/youtubepartnerVer y administrar sus elementos y el contenido asociado en YouTube
https://www.googleapis.com/auth/youtubepartner-channel-auditPermite ver información privada de tu canal de YouTube que sea relevante durante el proceso de auditoría con un socio de YouTube.

El documento Alcances de la API de OAuth 2.0 contiene una lista completa de los permisos que puedes usar para acceder a las APIs de Google.

Obtén tokens de acceso de OAuth 2.0

En los siguientes pasos, se muestra cómo tu aplicación interactúa con el servidor de OAuth 2.0 de Google para obtener el consentimiento de un usuario y realizar una solicitud a la API en su nombre. Tu aplicación debe tener ese consentimiento para poder ejecutar una solicitud a la API de Google que requiera autorización del usuario.

Paso 1: Redirecciona al servidor OAuth 2.0 de Google

Para solicitar permiso para acceder a los datos de un usuario, redirecciona al usuario al servidor de OAuth 2.0 de Google.

Extremos de OAuth 2.0

Genera una URL para solicitar acceso desde el extremo de OAuth 2.0 de Google en https://accounts.google.com/o/oauth2/v2/auth. Se puede acceder a este extremo a través de HTTPS. Se rechazan las conexiones HTTP simples.

El servidor de autorización de Google admite los siguientes parámetros de cadena de consulta para aplicaciones de servidor web:

Parámetros
client_id Obligatorio

El ID de cliente de tu aplicación. Puedes encontrar este valor en el archivo API Console Credentials page.

redirect_uri Obligatorio

Determina a dónde redirecciona el servidor de la API al usuario después de que completa el flujo de autorización. El valor debe coincidir exactamente con uno de los URIs de redireccionamiento autorizados para el cliente de OAuth 2.0, que configuraste en el API Consolede tu cliente Credentials page. Si este valor no coincide con un URI de redireccionamiento autorizado para el client_id proporcionado, recibirás un error redirect_uri_mismatch.

Ten en cuenta que el esquema http o https, el caso y la barra final ('/') deben coincidir.

response_type Obligatorio

Las aplicaciones de JavaScript deben establecer el valor del parámetro en token. Este valor le indica al servidor de autorización de Google que devuelva el token de acceso como un par name=value en el identificador de fragmento del URI (#) al que se redirecciona al usuario después de completar el proceso de autorización.

scope Obligatorio

Es una lista de permisos delimitados por espacios que identifican los recursos a los que puede acceder tu aplicación en nombre del usuario. Estos valores informan la pantalla de consentimiento que Google muestra al usuario.

Los alcances permiten que la aplicación solo solicite acceso a los recursos que necesita, al tiempo que permiten a los usuarios controlar el nivel de acceso que otorgan a tu aplicación. Por lo tanto, existe una relación inversa entre la cantidad de permisos solicitados y la probabilidad de obtener el consentimiento del usuario.

La versión 3 de la API de YouTube Data usa los siguientes permisos:

Permisos
https://www.googleapis.com/auth/youtubeAdministrar tu cuenta de YouTube
https://www.googleapis.com/auth/youtube.channel-memberships.creatorVer una lista de los miembros actuales y activos de su canal, su nivel actual y el momento en que se hicieron miembros
https://www.googleapis.com/auth/youtube.force-sslVea, edite y borre de forma permanente sus videos, calificaciones, comentarios y subtítulos de YouTube
https://www.googleapis.com/auth/youtube.readonlyPermite ver tu cuenta de YouTube.
https://www.googleapis.com/auth/youtube.uploadPermite administrar tus videos de YouTube.
https://www.googleapis.com/auth/youtubepartnerVer y administrar sus elementos y el contenido asociado en YouTube
https://www.googleapis.com/auth/youtubepartner-channel-auditPermite ver información privada de tu canal de YouTube que sea relevante durante el proceso de auditoría con un socio de YouTube.

El documento Alcances de la API de OAuth 2.0 proporciona una lista completa de los permisos que puedes usar para acceder a las APIs de Google.

Te recomendamos que tu aplicación solicite acceso a los permisos de autorización en el contexto cada vez que sea posible. Cuando solicitas acceso a los datos del usuario en contexto, a través de la autorización incremental, ayudas a los usuarios a comprender con mayor facilidad por qué tu aplicación necesita el acceso que solicita.

state Recomendado

Especifica cualquier valor de cadena que use tu aplicación para mantener el estado entre tu solicitud de autorización y la respuesta del servidor de autorización. El servidor muestra el valor exacto que envías como un par name=value en el identificador de fragmento de URL (#) de redirect_uri después de que el usuario acepta o rechaza la solicitud de acceso de tu aplicación.

Puedes usar este parámetro para varios fines, como dirigir al usuario al recurso correcto en tu aplicación, enviar nonces y mitigar la falsificación de solicitudes entre sitios. Dado que se puede adivinar tu redirect_uri, usar un valor state puede aumentar tu seguridad de que una conexión entrante es el resultado de una solicitud de autenticación. Si generas una cadena aleatoria o codificas el hash de una cookie o algún otro valor que capture el estado del cliente, puedes validar la respuesta para asegurarte además de que la solicitud y la respuesta se originen en el mismo navegador, lo que proporciona protección contra ataques como la falsificación de solicitudes entre sitios. Consulta la documentación de OpenID Connect para ver un ejemplo de cómo crear y confirmar un token state.

include_granted_scopes Opcional

Permite que las aplicaciones usen la autorización incremental para solicitar acceso a permisos adicionales en el contexto. Si estableces el valor de este parámetro en true y se otorga la solicitud de autorización, el nuevo token de acceso también abarcará cualquier permiso al que el usuario le haya otorgado acceso a la aplicación anteriormente. Consulta la sección sobre la autorización incremental para ver ejemplos.

login_hint Opcional

Si tu aplicación sabe qué usuario intenta autenticarse, puede usar este parámetro para proporcionar una sugerencia al servidor de autenticación de Google. El servidor usa la sugerencia para simplificar el flujo de acceso, ya sea completando previamente el campo de correo electrónico en el formulario de acceso o seleccionando la sesión de acceso múltiple adecuada.

Establece el valor del parámetro en una dirección de correo electrónico o un identificador sub, que es equivalente al ID de Google del usuario.

prompt Opcional

Es una lista de instrucciones delimitadas por espacios que distingue mayúsculas de minúsculas para presentarle al usuario. Si no especificas este parámetro, se le solicitará al usuario solo la primera vez que tu proyecto solicite acceso. Consulta Cómo solicitar el consentimiento nuevamente para obtener más información.

Los valores posibles son:

none No muestres ninguna pantalla de autenticación o consentimiento. No se debe especificar con otros valores.
consent Solicita el consentimiento del usuario.
select_account Pídele al usuario que seleccione una cuenta.

Ejemplo de redireccionamiento al servidor de autorización de Google

A continuación, se muestra una URL de ejemplo, con saltos de línea y espacios para facilitar la lectura. La URL solicita acceso a un permiso que permite recuperar los datos de YouTube del usuario. Usa la autorización incremental (include_granted_scopes=true) para garantizar que el nuevo token de acceso cubra cualquier ámbito al que el usuario le haya otorgado acceso a la aplicación anteriormente. En el ejemplo, también se configuran varios otros parámetros.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
 client_id=client_id

Después de crear la URL de solicitud, redirecciona al usuario a ella.

Código de muestra de JavaScript

En el siguiente fragmento de JavaScript, se muestra cómo iniciar el flujo de autorización en JavaScript sin usar la biblioteca cliente de las APIs de Google para JavaScript. Dado que este extremo de OAuth 2.0 no admite el uso compartido de recursos entre dominios (CORS), el fragmento crea un formulario que abre la solicitud a ese extremo.

/*
 * Create form to request access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client_id': 'YOUR_CLIENT_ID',
                'redirect_uri': 'YOUR_REDIRECT_URI',
                'response_type': 'token',
                'scope': 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly',
                'include_granted_scopes': 'true',
                'state': 'pass-through value'};

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

Paso 2: Google le solicita consentimiento al usuario

En este paso, el usuario decide si otorgarle a tu aplicación el acceso solicitado. En esta etapa, Google muestra una ventana de consentimiento que muestra el nombre de tu aplicación y los servicios de la API de Google a los que solicita permiso para acceder con las credenciales de autorización del usuario, y un resumen de los permisos de acceso que se otorgarán. Luego, el usuario puede consentir otorgar acceso a uno o más permisos solicitados por tu aplicación o rechazar la solicitud.

Tu aplicación no necesita hacer nada en esta etapa, ya que espera la respuesta del servidor de OAuth 2.0 de Google que indique si se otorgó algún acceso. Esa respuesta se explica en el siguiente paso.

Errores

Es posible que las solicitudes al extremo de autorización de OAuth 2.0 de Google muestren mensajes de error para el usuario en lugar de los flujos de autenticación y autorización esperados. A continuación, se indican los códigos de error comunes y las resoluciones sugeridas.

admin_policy_enforced

La Cuenta de Google no puede autorizar uno o más permisos solicitados debido a las políticas de su administrador de Google Workspace. Consulta el artículo de ayuda del Administrador de Google Workspace Controla qué apps internas y de terceros acceden a los datos de Google Workspace para obtener más información sobre cómo un administrador puede restringir el acceso a todos los permisos o a los permisos sensibles y restringidos hasta que se otorgue acceso de forma explícita a tu ID de cliente de OAuth.

disallowed_useragent

El extremo de autorización se muestra dentro de un usuario-agente incorporado que no está permitido por las Políticas de OAuth 2.0 de Google.

Android

Es posible que los desarrolladores de Android encuentren este mensaje de error cuando abran solicitudes de autorización en android.webkit.WebView. En su lugar, los desarrolladores deben usar bibliotecas de Android, como Acceso con Google para Android o AppAuth para Android de la OpenID Foundation.

Es posible que los desarrolladores web encuentren este error cuando una app para Android abre un vínculo web general en un usuario-agente incorporado y un usuario navega al extremo de autorización de OAuth 2.0 de Google desde tu sitio. Los desarrolladores deben permitir que los vínculos generales se abran en el controlador de vínculos predeterminado del sistema operativo, que incluye los controladores de Android App Links o la app de navegador predeterminada. La biblioteca de Android Custom Tabs también es una opción compatible.

iOS

Es posible que los desarrolladores de iOS y macOS encuentren este error cuando abran solicitudes de autorización en WKWebView. En su lugar, los desarrolladores deben usar bibliotecas de iOS, como Acceso con Google para iOS o AppAuth para iOS de OpenID Foundation.

Es posible que los desarrolladores web encuentren este error cuando una app para iOS o macOS abra un vínculo web general en un usuario-agente incorporado y un usuario navegue al extremo de autorización de OAuth 2.0 de Google desde tu sitio. Los desarrolladores deben permitir que los vínculos generales se abran en el controlador de vínculos predeterminado del sistema operativo, que incluye los controladores de vínculos universales o la app de navegador predeterminada. La biblioteca SFSafariViewController también es una opción compatible.

org_internal

El ID de cliente de OAuth en la solicitud forma parte de un proyecto que limita el acceso a las Cuentas de Google en una organización de Google Cloud específica. Para obtener más información sobre esta opción de configuración, consulta la sección Tipo de usuario en el artículo de ayuda Cómo configurar tu pantalla de consentimiento de OAuth.

invalid_client

El origen desde el que se realizó la solicitud no está autorizado para este cliente. Consulta origin_mismatch.

invalid_grant

Cuando se usa la autorización incremental, es posible que el token haya vencido o se haya invalidado. Vuelve a autenticar al usuario y solicita su consentimiento para obtener tokens nuevos. Si sigues viendo este error, asegúrate de que tu aplicación esté configurada correctamente y de que uses los tokens y parámetros correctos en tu solicitud. De lo contrario, es posible que se haya borrado o inhabilitado la cuenta de usuario.

origin_mismatch

Es posible que el esquema, el dominio o el puerto del código JavaScript que genera la solicitud de autorización no coincidan con un URI de origen de JavaScript autorizado registrado para el ID de cliente de OAuth. Revisa los orígenes de JavaScript autorizados en Google API Console Credentials page.

redirect_uri_mismatch

El redirect_uri que se pasó en la solicitud de autorización no coincide con un URI de redireccionamiento autorizado para el ID de cliente de OAuth. Revisa los URIs de redireccionamiento autorizados en Google API Console Credentials page.

Es posible que el esquema, el dominio o el puerto del código JavaScript que genera la solicitud de autorización no coincidan con un URI de origen de JavaScript autorizado registrado para el ID de cliente de OAuth. Revisa los orígenes autorizados de JavaScript en Google API Console Credentials page.

El parámetro redirect_uri puede hacer referencia al flujo fuera de banda (OOB) de OAuth que dejó de estar disponible y ya no es compatible. Consulta la guía de migración para actualizar tu integración.

invalid_request

Se produjo un error con la solicitud que realizaste. Esto puede deberse a varios motivos:

  • La solicitud no tenía el formato correcto
  • Faltaban parámetros obligatorios en la solicitud
  • La solicitud usa un método de autorización que Google no admite. Verifica que tu integración de OAuth use un método de integración recomendado

Paso 3: Controla la respuesta del servidor de OAuth 2.0

Extremos de OAuth 2.0

El servidor de OAuth 2.0 envía una respuesta al redirect_uri especificado en tu solicitud de token de acceso.

Si el usuario aprueba la solicitud, la respuesta contendrá un token de acceso. Si no lo aprueba, entonces esta contendrá un mensaje de error. El token de acceso o el mensaje de error se devuelven en el fragmento de hash del URI de redireccionamiento, como se muestra a continuación:

  • Una respuesta de token de acceso:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    Además del parámetro access_token, la cadena de fragmento también contiene el parámetro token_type, que siempre se establece en Bearer, y el parámetro expires_in, que especifica la vida útil del token, en segundos. Si se especificó el parámetro state en la solicitud de token de acceso, su valor también se incluye en la respuesta.

  • Una respuesta de error:
    https://oauth2.example.com/callback#error=access_denied

Ejemplo de respuesta del servidor de OAuth 2.0

Para probar este flujo, haz clic en la siguiente URL de ejemplo, que solicita acceso de solo lectura para ver los metadatos de los archivos de tu Google Drive y acceso de solo lectura para ver los eventos de tu Calendario de Google:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback&
 client_id=client_id

Después de completar el flujo de OAuth 2.0, se te redireccionará a http://localhost/oauth2callback. Esa URL mostrará un error 404 NOT FOUND, a menos que tu máquina local entregue un archivo en esa dirección. En el siguiente paso, se proporcionan más detalles sobre la información que se muestra en el URI cuando se redirecciona al usuario a tu aplicación.

Paso 4: Verifica qué permisos otorgaron los usuarios

Cuando solicites varios permisos a la vez, es posible que los usuarios no otorguen todos los permisos que solicita tu app. Tu app siempre debe verificar qué permisos otorgó el usuario y controlar cualquier denegación de permisos inhabilitando las funciones relevantes. Consulta Cómo controlar los permisos detallados para obtener más información.

Extremos de OAuth 2.0

Para verificar si el usuario otorgó a tu aplicación acceso a un alcance en particular, examina el campo scope en la respuesta del token de acceso. Los permisos de acceso que otorga el access_token expresados como una lista de cadenas separadas por espacios y sensibles a mayúsculas y minúsculas.

Por ejemplo, la siguiente respuesta de muestra del token de acceso indica que el usuario le otorgó a tu aplicación acceso a los permisos de eventos de Calendario y actividad de solo lectura de Drive:

  {
    "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
    "expires_in": 3920,
    "token_type": "Bearer",
    "scope": "https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly",
    "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
  }

Cómo llamar a las APIs de Google

Extremos de OAuth 2.0

Una vez que tu aplicación obtenga un token de acceso, podrás usarlo para realizar llamadas a una API de Google en nombre de una cuenta de usuario determinada si se otorgaron los permisos de acceso que requiere la API. Para ello, incluye el token de acceso en una solicitud a la API con un parámetro de consulta access_token o un valor Bearer de encabezado HTTP Authorization. Cuando sea posible, se prefiere el encabezado HTTP, ya que las cadenas de consulta suelen ser visibles en los registros del servidor. En la mayoría de los casos, puedes usar una biblioteca cliente para configurar tus llamadas a las APIs de Google (por ejemplo, cuando llamas a la API de YouTube Live Streaming).

Ten en cuenta que la API de YouTube Live Streaming no admite el flujo de cuentas de servicio. Dado que no hay forma de vincular una cuenta de servicio a una cuenta de YouTube, los intentos de autorizar solicitudes con este flujo generarán un error NoLinkedYouTubeAccount.

Puedes probar todas las APIs de Google y ver sus permisos en OAuth 2.0 Playground.

Ejemplos de HTTP GET

Una llamada al extremo liveBroadcasts.list (la API de YouTube Live Streaming) con el encabezado HTTP Authorization: Bearer podría verse de la siguiente manera. Ten en cuenta que debes especificar tu propio token de acceso:

GET /youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Esta es una llamada a la misma API para el usuario autenticado con el parámetro de cadena de consulta access_token:

GET https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true

Ejemplos de curl

Puedes probar estos comandos con la aplicación de línea de comandos curl. A continuación, se muestra un ejemplo que usa la opción de encabezado HTTP (preferida):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true

O bien, la opción de parámetro de cadena de consulta:

curl https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true

Código de muestra de JavaScript

En el siguiente fragmento de código, se muestra cómo usar el CORS (uso compartido de recursos entre dominios) para enviar una solicitud a una API de Google. En este ejemplo, no se usa la biblioteca cliente de las APIs de Google para JavaScript. Sin embargo, incluso si no usas la biblioteca cliente, es probable que la guía de compatibilidad con CORS de la documentación de esa biblioteca te ayude a comprender mejor estas solicitudes.

En este fragmento de código, la variable access_token representa el token que obtuviste para realizar solicitudes a la API en nombre del usuario autorizado. En el ejemplo completo, se muestra cómo almacenar ese token en el almacenamiento local del navegador y recuperarlo cuando se realiza una solicitud a la API.

var xhr = new XMLHttpRequest();
xhr.open('GET',
    'https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id,snippet&mine=true' +
    'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
  console.log(xhr.response);
};
xhr.send(null);

Ejemplo completo

Extremos de OAuth 2.0

En esta muestra de código, se muestra cómo completar el flujo de OAuth 2.0 en JavaScript sin usar la biblioteca cliente de las APIs de Google para JavaScript. El código es para una página HTML que muestra un botón para probar una solicitud a la API. Si haces clic en el botón, el código verifica si la página almacenó un token de acceso a la API en el almacenamiento local de tu navegador. Si es así, ejecuta la solicitud a la API. De lo contrario, se inicia el flujo de OAuth 2.0.

En el caso del flujo de OAuth 2.0, la página sigue estos pasos:

  1. Dirige al usuario al servidor de OAuth 2.0 de Google, que solicita acceso a los permisos https://www.googleapis.com/auth/youtube.force-ssl y https://www.googleapis.com/auth/calendar.readonly.
  2. Después de otorgar (o denegar) acceso a uno o más permisos solicitados, se redirecciona al usuario a la página original, que analiza el token de acceso de la cadena de identificador de fragmento.
  3. La página verifica a qué permisos el usuario le otorgó acceso a la aplicación.
  4. Si el usuario otorgó acceso a los permisos solicitados, la página usa el token de acceso para realizar la solicitud de API de muestra.

    Esta solicitud a la API llama al método liveBroadcasts.list de la API de YouTube Data para recuperar una lista de transmisiones de video del canal de YouTube del usuario autorizado.

  5. Si la solicitud se ejecuta correctamente, la respuesta de la API se registra en la consola de depuración del navegador.

Puedes revocar el acceso a la app a través de la página Permisos de tu Cuenta de Google. La app aparecerá como Demostración de OAuth 2.0 para la documentación de la API de Google.

Para ejecutar este código de forma local, debes establecer valores para las variables YOUR_CLIENT_ID y YOUR_REDIRECT_URI que correspondan a tus credenciales de autorización. La variable YOUR_REDIRECT_URI debe establecerse en la misma URL en la que se entrega la página. El valor debe coincidir exactamente con uno de los URIs de redireccionamiento autorizados para el cliente de OAuth 2.0, que configuraste en API Console Credentials page. Si este valor no coincide con un URI autorizado, recibirás un error redirect_uri_mismatch. Tu proyecto también debe haber habilitado la API adecuada para esta solicitud.

<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var fragmentString = location.hash.substring(1);
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0 && params['state']) {
    if (params['state'] == localStorage.getItem('state')) {
      localStorage.setItem('oauth2-test-params', JSON.stringify(params) );

      trySampleRequest();
    } else {
      console.log('State mismatch. Possible CSRF attack');
    }
  }

  // Function to generate a random state value
  function generateCryptoRandomState() {
    const randomValues = new Uint32Array(2);
    window.crypto.getRandomValues(randomValues);

    // Encode as UTF-8
    const utf8Encoder = new TextEncoder();
    const utf8Array = utf8Encoder.encode(
      String.fromCharCode.apply(null, randomValues)
    );

    // Base64 encode the UTF-8 data
    return btoa(String.fromCharCode.apply(null, utf8Array))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) { 
      // User authorized the request. Now, check which scopes were granted.
      if (params['scope'].includes('https://www.googleapis.com/auth/drive.metadata.readonly')) {
        // User authorized read-only Drive activity permission.
        // Calling the APIs, etc.
        var xhr = new XMLHttpRequest();
        xhr.open('GET',
          'https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id,snippet&mine=true' +
          'access_token=' + params['access_token']);
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.response);
          } else if (xhr.readyState === 4 && xhr.status === 401) {
            // Token invalid, so prompt for user permission.
            oauth2SignIn();
          }
        };
        xhr.send(null);
      }
      else {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
        console.log('User did not authorize read-only Drive activity permission.');
      }

      // Check if user authorized Calendar read permission.
      if (params['scope'].includes('https://www.googleapis.com/auth/calendar.readonly')) {
        // User authorized Calendar read permission.
        // Calling the APIs, etc.
        console.log('User authorized Calendar read permission.');
      }
      else {
        // User didn't authorize Calendar read permission.
        // Update UX and application accordingly
        console.log('User did not authorize Calendar read permission.');
      } 
    } else {
      oauth2SignIn();
    }
  }

  /*
   * Create form to request access token from Google's OAuth 2.0 server.
   */
  function oauth2SignIn() {
    // create random state value and store in local storage
    var state = generateCryptoRandomState();
    localStorage.setItem('state', state);

    // Google's OAuth 2.0 endpoint for requesting an access token
    var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly',
                  'state': state,
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

Reglas de validación de orígenes de JavaScript

Google aplica las siguientes reglas de validación a los orígenes de JavaScript para ayudar a los desarrolladores a mantener la seguridad de sus aplicaciones. Los orígenes de JavaScript deben cumplir con estas reglas. Consulta la sección 3 de la RFC 3986 para obtener la definición de dominio, host y esquema que se mencionan a continuación.

Reglas de validación
Esquema

Los orígenes de JavaScript deben usar el esquema HTTPS, no el HTTP simple. Los URIs de localhost (incluidos los URIs de direcciones IP de localhost) están exentos de esta regla.

Host

Los hosts no pueden ser direcciones IP sin procesar. Las direcciones IP de localhost están exentas de esta regla.

Dominio
  • Los TLD del host (dominios de nivel superior) deben pertenecer a la lista de sufijos públicos.
  • Los dominios de host no pueden ser “googleusercontent.com”.
  • Los orígenes de JavaScript no pueden contener dominios de acortadores de URL (p.ej., goo.gl) a menos que la app sea propietaria del dominio.
  • Userinfo

    Los orígenes de JavaScript no pueden contener el subcomponente userinfo.

    Ruta de acceso

    Los orígenes de JavaScript no pueden contener el componente de ruta de acceso.

    Consulta

    Los orígenes de JavaScript no pueden contener el componente de consulta.

    Fragmento

    Los orígenes de JavaScript no pueden contener el componente de fragmento.

    Caracteres Los orígenes de JavaScript no pueden contener ciertos caracteres, incluidos los siguientes:
    • Caracteres comodín ('*')
    • Caracteres ASCII no imprimibles
    • Codificación de porcentaje no válida (cualquier codificación de porcentaje que no siga el formato de codificación de URL de un signo de porcentaje seguido de dos dígitos hexadecimales)
    • Caracteres nulos (un carácter NULL codificado, p.ej., %00, %C0%80)

    Autorización incremental

    En el protocolo OAuth 2.0, tu app solicita autorización para acceder a los recursos, que se identifican por permisos. Se considera una práctica recomendada de experiencia del usuario solicitar la autorización para los recursos en el momento en que los necesitas. Para habilitar esa práctica, el servidor de autorización de Google admite la autorización incremental. Esta función te permite solicitar ámbitos a medida que sean necesarios y, si el usuario otorga permiso para el ámbito nuevo, muestra un código de autorización que se puede intercambiar por un token que contiene todos los ámbitos que el usuario otorgó al proyecto.

    Por ejemplo, supongamos que una app recupera datos del canal de YouTube del usuario autenticado y también le permite recuperar datos de YouTube Analytics a través de un flujo especial. En este caso, en el momento del acceso, la app podría solicitar acceso solo al permiso https://www.googleapis.com/auth/youtube.force-ssl. Sin embargo, si el usuario intentara acceder a los datos de Analytics de su canal, la app también podría solicitar acceso al alcance https://www.googleapis.com/auth/yt-analytics.readonly.

    Las siguientes reglas se aplican a un token de acceso obtenido de una autorización incremental:

    • El token se puede usar para acceder a los recursos correspondientes a cualquiera de los permisos integrados en la nueva autorización combinada.
    • Cuando usas el token de actualización para la autorización combinada para obtener un token de acceso, este representa la autorización combinada y se puede usar para cualquiera de los valores de scope incluidos en la respuesta.
    • La autorización combinada incluye todos los permisos que el usuario otorgó al proyecto de la API, incluso si los permisos se solicitaron desde diferentes clientes. Por ejemplo, si un usuario otorga acceso a un permiso con el cliente para computadoras de una aplicación y, luego, otorga otro permiso a la misma aplicación a través de un cliente para dispositivos móviles, la autorización combinada incluirá ambos permisos.
    • Si revocas un token que representa una autorización combinada, se revocará de forma simultánea el acceso a todos los ámbitos de esa autorización en nombre del usuario asociado.

    En los siguientes ejemplos de código, se muestra cómo agregar permisos a un token de acceso existente. Este enfoque permite que tu app evite tener que administrar varios tokens de acceso.

    Extremos de OAuth 2.0

    En este ejemplo, la aplicación que realiza la llamada solicita acceso para recuperar los datos de YouTube del usuario, además de cualquier otro acceso que el usuario ya le haya otorgado a la aplicación.

    Para agregar permisos a un token de acceso existente, incluye el parámetro include_granted_scopes en tu solicitud al servidor de OAuth 2.0 de Google.

    En el siguiente fragmento de código, se muestra cómo hacerlo. El fragmento supone que almacenaste los permisos para los que es válido tu token de acceso en el almacenamiento local del navegador. (El código del ejemplo completo almacena una lista de permisos para los que el token de acceso es válido configurando la propiedad oauth2-test-params.scope en el almacenamiento local del navegador).

    El fragmento compara los permisos para los que es válido el token de acceso con el permiso que deseas usar para una consulta en particular. Si el token de acceso no cubre ese permiso, se inicia el flujo de OAuth 2.0. Aquí, la función oauth2SignIn es la misma que la que se proporcionó en el paso 2 (y que se proporciona más adelante en el ejemplo completo).

    var SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

    Cómo revocar un token

    En algunos casos, es posible que un usuario desee revocar el acceso otorgado a una aplicación. Un usuario puede revocar el acceso en Configuración de la cuenta. Consulta la sección Cómo quitar el acceso de un sitio o una app del documento de asistencia Sitios y apps de terceros con acceso a tu cuenta para obtener más información.

    También es posible que una aplicación revoque de forma programática el acceso que se le otorgó. La revocación programática es importante en los casos en que un usuario cancela su suscripción, quita una aplicación o los recursos de la API que requiere una app cambiaron de forma significativa. En otras palabras, parte del proceso de eliminación puede incluir una solicitud a la API para garantizar que se quiten los permisos otorgados anteriormente a la aplicación.

    Extremos de OAuth 2.0

    Para revocar un token de manera programática, tu aplicación envía una solicitud a https://oauth2.googleapis.com/revoke y, además, incluye el token como parámetro:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    El token puede ser un token de acceso o un token de actualización. Si el token es un token de acceso y tiene un token de actualización correspondiente, este también se revocará.

    Si la revocación se procesa correctamente, el código de estado HTTP de la respuesta es 200. Para las condiciones de error, se muestra un código de estado HTTP 400 junto con un código de error.

    En el siguiente fragmento de JavaScript, se muestra cómo revocar un token en JavaScript sin usar la biblioteca cliente de las APIs de Google para JavaScript. Dado que el extremo OAuth 2.0 de Google para revocar tokens no admite el uso compartido de recursos entre dominios (CORS), el código crea un formulario y lo envía al extremo en lugar de usar el método XMLHttpRequest() para publicar la solicitud.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }

    Implementa la Protección integral de la cuenta

    Un paso adicional que debes seguir para proteger las cuentas de tus usuarios es implementar la Protección entre cuentas con el servicio de Protección entre cuentas de Google. Este servicio te permite suscribirte a notificaciones de eventos de seguridad que proporcionan información a tu aplicación sobre cambios importantes en la cuenta de usuario. Luego, puedes usar la información para tomar medidas según cómo decidas responder a los eventos.

    Estos son algunos ejemplos de los tipos de eventos que el servicio de Protección entre cuentas de Google envía a tu app:

    • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
    • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
    • https://schemas.openid.net/secevent/risc/event-type/account-disabled

    Consulta la página Protege las cuentas de usuario con la Protección integral de la cuenta para obtener más información sobre cómo implementar la Protección integral de la cuenta y ver la lista completa de eventos disponibles.