Guía de migración del flujo fuera de banda (OOB)

Descripción general

El 16 de febrero de 2022, anunciamos que planeábamos hacer que las interacciones de OAuth de Google fueran más seguras mediante el uso de flujos de OAuth más seguros. Esta guía te ayuda a comprender los cambios y los pasos necesarios para migrar de forma correcta del flujo fuera de banda (OOB) de OAuth a las alternativas admitidas.

Este esfuerzo es una medida de protección contra los ataques de phishing y de suplantación de identidad de apps durante las interacciones con los extremos de autorización de OAuth 2.0 de Google.

¿Qué es OOB?

OAuth fuera de banda (OOB), también conocido como la opción de copiar y pegar manual, es un flujo heredado desarrollado para admitir clientes nativos que no tienen un URI de redireccionamiento para aceptar las credenciales después de que un usuario aprueba una solicitud de consentimiento de OAuth. El flujo fuera del alcance plantea un riesgo de phishing remoto, y los clientes deben migrar a un método alternativo para protegerse contra esta vulnerabilidad.

El flujo fuera del alcance dejará de estar disponible para todos los tipos de clientes, es decir, aplicaciones web, Android, iOS, Universal Windows Platform (UWP), apps para Chrome, TVs y dispositivos de entrada limitada, y apps para computadoras.

Fechas clave de cumplimiento

  • 28 de febrero de 2022: Se bloqueó el nuevo uso de OAuth para el flujo fuera del alcance
  • 5 de septiembre de 2022: Es posible que se muestre un mensaje de advertencia para el usuario a las solicitudes de OAuth que no cumplan con los requisitos
  • 3 de octubre de 2022: El flujo fuera del navegador dejará de estar disponible para los clientes de OAuth creados antes del 28 de febrero de 2022.
  • 31 de enero de 2023: Se bloquean todos los clientes existentes (incluidos los clientes exentos).

Se mostrará un mensaje de error para el usuario en el caso de las solicitudes que no cumplan con los requisitos. El mensaje les informará a los usuarios que la app está bloqueada mientras se muestra el correo electrónico de asistencia que registraste en la pantalla de consentimiento de OAuth en la Consola de API de Google.

Existen dos pasos principales para completar el proceso de migración:
  1. Determina si te afecta.
  2. Migra a una alternativa más segura si te afecta.

Determina si te afecta

Esta baja solo se aplica a las apps de producción (es decir, las apps con el estado de publicación establecido como En producción). El flujo seguirá funcionando para las apps con el estado de publicación de prueba.

Revisa el estado de publicación en el de OAuth de la y continúa con el siguiente paso si usas el flujo fuera del alcance en un proyecto con un estado de publicación "En producción".

Cómo determinar si tu app usa el flujo fuera del dispositivo

Inspecciona el código de tu app o la llamada de red saliente (en caso de que tu app use una biblioteca de OAuth) para determinar si la solicitud de autorización de OAuth de Google que realiza tu app usa un valor de URI de redireccionamiento fuera del alcance.

Inspecciona el código de tu aplicación

Revisa la sección del código de tu aplicación en la que realizas llamadas a los extremos de autorización de OAuth de Google y determina si el parámetro redirect_uri tiene alguno de los siguientes valores:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
Una solicitud de flujo de redireccionamiento fuera del alcance de ejemplo se verá como la siguiente:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

Cómo inspeccionar la llamada de red saliente

El método para inspeccionar las llamadas de red variará según el tipo de cliente de la aplicación.
Mientras inspeccionas las llamadas de red, busca solicitudes enviadas a los extremos de autorización de OAuth de Google y determina si el parámetro redirect_uri tiene alguno de los siguientes valores:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
Una solicitud de flujo de redireccionamiento fuera del alcance de ejemplo se verá como la siguiente:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

Migra a una alternativa segura

Clientes para dispositivos móviles (Android / iOS)

Si determinas que tu app usa el flujo fuera del alcance con un tipo de cliente de OAuth de Android o iOS, debes migrar a los SDKs recomendados (Android, iOS).

El SDK facilita el acceso a las APIs de Google y controla todas las llamadas a los extremos de autorización de OAuth 2.0 de Google.

En los vínculos de documentación que se indican a continuación, se proporciona información para usar los SDKs recomendados y acceder a las APIs de Google sin usar un URI de redireccionamiento fuera del perímetro.

Accede a las APIs de Google en Android

Acceso del cliente

En el siguiente ejemplo, se muestra cómo acceder a las APIs de Google en el cliente en Android con la biblioteca de Android de Google Identity Services recomendada.

  List requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
    AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build();
    Identity.getAuthorizationClient(activity)
            .authorize(authorizationRequest)
            .addOnSuccessListener(
                authorizationResult -> {
                  if (authorizationResult.hasResolution()) {
                    // Access needs to be granted by the user
                    PendingIntent pendingIntent = authorizationResult.getPendingIntent();
                    try {
    startIntentSenderForResult(pendingIntent.getIntentSender(),
    REQUEST_AUTHORIZE, null, 0, 0, 0, null);
                    } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
                    }
                  } else {
                    // Access already granted, continue with user action
                    saveToDriveAppFolder(authorizationResult);
                  }
                })
            .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

Pasa el authorizationResult a tu método definido para guardar contenido en la carpeta de Drive del usuario. authorizationResult tiene el método getAccessToken() que muestra el token de acceso.

Acceso del servidor (sin conexión)
En el siguiente ejemplo, se muestra cómo acceder a las APIs de Google en el servidor de Android.
  List requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
    AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()
    .requestOfflineAccess(webClientId)
            .setRequestedScopes(requestedScopes)
            .build();
    Identity.getAuthorizationClient(activity)
            .authorize(authorizationRequest)
            .addOnSuccessListener(
                authorizationResult -> {
                  if (authorizationResult.hasResolution()) {
                    // Access needs to be granted by the user
                    PendingIntent pendingIntent = authorizationResult.getPendingIntent();
                    try {
    startIntentSenderForResult(pendingIntent.getIntentSender(),
    REQUEST_AUTHORIZE, null, 0, 0, 0, null);
                    } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
                    }
                  } else {
                    String authCode = authorizationResult.getServerAuthCode();
                  }
                })
            .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

authorizationResult tiene el método getServerAuthCode() que muestra el código de autorización que puedes enviar a tu backend para obtener un token de acceso y actualización.

Cómo acceder a las APIs de Google en una app para iOS

Acceso del cliente

En el siguiente ejemplo, se muestra cómo acceder a las APIs de Google en el cliente en iOS.

user.authentication.do { authentication, error in
  guard error == nil else { return }
  guard let authentication = authentication else { return }
  
  // Get the access token to attach it to a REST or gRPC request.
  let accessToken = authentication.accessToken
  
  // Or, get an object that conforms to GTMFetcherAuthorizationProtocol for
  // use with GTMAppAuth and the Google APIs client library.
  let authorizer = authentication.fetcherAuthorizer()
}

Usa el token de acceso para llamar a la API. Para ello, inclúyelo en el encabezado de una solicitud REST o gRPC (Authorization: Bearer ACCESS_TOKEN) o usa el autorizador de recuperación (GTMFetcherAuthorizationProtocol) con la biblioteca cliente de las APIs de Google para Objective-C de REST.

Revisa la guía de acceso del cliente para obtener información sobre cómo acceder a las APIs de Google del cliente. sobre cómo acceder a las APIs de Google del cliente.

Acceso del servidor (sin conexión)
En el siguiente ejemplo, se muestra cómo acceder a las APIs de Google en el servidor para admitir un cliente de iOS.
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
  guard error == nil else { return }
  guard let user = user else { return }
  
  // request a one-time authorization code that your server exchanges for
  // an access token and refresh token
  let authCode = user.serverAuthCode
}

Revisa la guía de acceso del servidor para obtener información sobre cómo acceder a las APIs de Google desde el servidor.

Cliente de apps de Chrome

Si determinas que tu app usa el flujo fuera del alcance en el cliente de la app de Chrome, debes migrar a la API de Chrome Identity.

En el siguiente ejemplo, se muestra cómo obtener todos los contactos del usuario sin usar un URI de redireccionamiento fuera del alcance.

window.onload = function() {
  document.querySelector('button').addEventListener('click', function() {

  
  // retrieve access token
  chrome.identity.getAuthToken({interactive: true}, function(token) {
  
  // ..........


  // the example below shows how to use a retrieved access token with an appropriate scope
  // to call the Google People API contactGroups.get endpoint

  fetch(
    'https://people.googleapis.com/v1/contactGroups/all?maxMembers=20&key=API_KEY',
    init)
    .then((response) => response.json())
    .then(function(data) {
      console.log(data)
    });
   });
 });
};

Revisa la guía de la API de Chrome Identity para obtener más información sobre cómo acceder a los usuarios autenticados y llamar a los extremos de Google con la API de Chrome Identity.

Aplicación web

Si determinas que tu app usa el flujo fuera del alcance para una aplicación web, debes migrar a una de nuestras bibliotecas cliente de la API de Google. Las bibliotecas cliente para diferentes lenguajes de programación se enumeran aquí.

Las bibliotecas facilitan el acceso a las APIs de Google y controlan todas las llamadas a los extremos de Google.

Acceso del servidor (sin conexión)
El modo de acceso del servidor (sin conexión) requiere que hagas lo siguiente:
  • Activa un servidor y define un extremo de acceso público (el URI de redireccionamiento) para recibir el código de autorización.
  • Configura el URI de redireccionamiento en el de la

En el siguiente fragmento de código, se muestra un ejemplo de NodeJS para usar la API de Google Drive para mostrar una lista de los archivos de Google Drive de un usuario en el servidor sin usar un URI de redireccionamiento fuera del alcance.

async function main() {
  const server = http.createServer(async function (req, res) {

  if (req.url.startsWith('/oauth2callback')) {
    let q = url.parse(req.url, true).query;

    if (q.error) {
      console.log('Error:' + q.error);
    } else {
      
      // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      // Example of using Google Drive API to list filenames in user's Drive.
      const drive = google.drive('v3');
      drive.files.list({
        auth: oauth2Client,
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err1, res1) => {
        // TODO(developer): Handle response / error.
      });
    }
  }
}

Revisa la guía de apps web del servidor para obtener información sobre cómo acceder a las APIs de Google desde el servidor.

Acceso del cliente

En el siguiente fragmento de código, en JavaScript, se muestra un ejemplo del uso de la API de Google para acceder a los eventos de calendario del usuario en el lado del cliente.


// initTokenClient() initializes a new token client with your
// web app's client ID and the scope you need access to

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  
  // callback function to handle the token response
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) { 
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

Revisa la guía de apps web del cliente para obtener información sobre cómo acceder a las APIs de Google desde el cliente.

Cliente para computadoras

Si determinas que tu app usa el flujo fuera de banda en un cliente para computadoras de escritorio, debes migrar al uso del flujo de dirección IP de bucle invertido (localhost o 127.0.0.1).