Cómo manejar permisos detallados

Descripción general

Con los permisos detallados, los consumidores obtienen un control más preciso sobre los datos de la cuenta que eligen compartir con cada app. Además, benefician a usuarios y desarrolladores debido a que proporcionan un mayor control, transparencia y seguridad. Esta guía te ayudará a comprender los cambios y los pasos necesarios para actualizar de forma correcta tus aplicaciones a fin de controlar permisos detallados.

¿Qué es el permiso detallado?

Imagina que desarrollas una aplicación de productividad que solicita permisos de correo electrónico y de calendario. Es posible que los usuarios deseen usar tu aplicación solo para el Calendario de Google, pero no para Gmail. Con los permisos detallados de OAuth, los usuarios pueden optar por otorgar solo el permiso del Calendario de Google, pero no de Gmail. Cuando permites que los usuarios otorguen acceso a datos específicos, se minimiza la exposición de datos, refuerza la confianza y les brinda a los usuarios un control sobre su vida digital centrado en priorizar la privacidad. Es importante diseñar tu aplicación para manejar estas situaciones.

Cuando se solicita más de un alcance que no sea de acceso

Permisos de acceso y de no acceso

En el caso de las aplicaciones que solicitan permisos de acceso y sin acceso, los usuarios primero ven la página de consentimiento de los permisos de acceso (email, profile y openid). Una vez que los usuarios otorguen su consentimiento para compartir su información de identidad básica (nombre, dirección de correo electrónico y foto de perfil), los usuarios verán una pantalla de consentimiento detallada para los permisos que no requieren acceso. En este caso, la aplicación debe verificar qué permisos otorgan los usuarios y no puede asumir que los usuarios otorgan todos los permisos solicitados. En el siguiente ejemplo, la aplicación web solicita los tres permisos de acceso y un alcance sin acceso de Google Drive. Una vez que los usuarios otorguen su consentimiento para los permisos de acceso, verán la pantalla de consentimiento detallada de los permisos para Google Drive:

Permisos de acceso y de no acceso

Más de un permiso que no sea de acceso

Se mostrará una pantalla de consentimiento de permisos detallada a los usuarios cuando las aplicaciones soliciten más de un permiso sin acceso. Los usuarios pueden seleccionar los permisos que desean aprobar para compartirlos con la aplicación. A continuación, se muestra un ejemplo de una pantalla de consentimiento detallada que solicita acceso a los mensajes de Gmail del usuario y a los datos del Calendario de Google:

Más de un permiso que no sea de acceso

En el caso de las aplicaciones que solicitan solo permisos de acceso (email, profile y openid), la pantalla de consentimiento de los permisos #inspect-your-application-codegranular no es aplicable. Los usuarios pueden aprobar o rechazar la solicitud de acceso completa. En otras palabras, si las aplicaciones solo solicitan permisos de acceso (uno, dos o los tres), la pantalla de consentimiento detallado de permisos no es aplicable.

En el caso de las aplicaciones que solicitan solo un alcance que no sea de acceso, la pantalla de consentimiento detallada del permiso no es aplicable. En otras palabras, los usuarios aprueban o rechazan la solicitud completa, y no hay una casilla de verificación en la pantalla de consentimiento. En la siguiente tabla, se resume cuándo se muestra la pantalla de consentimiento de permisos en detalle.

Cantidad de permisos de acceso Cantidad de permisos sin acceso Pantalla de consentimiento de permisos detallada
1-3 0 No aplicable
1-3 1 o más Servicios
0 1 No aplicable
0 2 años o más Servicios

Determina si tus aplicaciones se ven afectadas

Revisa exhaustivamente todas las secciones de tu aplicación en las que se usan extremos de autorización de Google OAuth 2.0 para solicitudes de permisos. Presta atención a aquellos que soliciten varios permisos cuando activen las pantallas de consentimiento de permisos detalladas que se presentan a los usuarios. En esos casos, asegúrate de que tu código pueda manejar el caso en el que los usuarios solo autoricen algunos de los permisos.

Cómo determinar si tu aplicación usa varios permisos

Inspecciona el código de tu app o la llamada de red saliente para determinar si las solicitudes de autorización de OAuth 2.0 de Google que realiza tu app harán que se muestre la pantalla de consentimiento de permisos detallada.

Inspecciona el código de tu aplicación

Revisa las secciones del código de la aplicación en las que realizas llamadas a los extremos de autorización de OAuth de Google para solicitar permiso a los usuarios. Si usas una de las bibliotecas cliente de la API de Google, a menudo puedes ver qué alcances solicita tu aplicación en los pasos de inicialización del cliente. En la siguiente sección, se muestran algunos ejemplos. Debes consultar la documentación de los SDK que usa tu aplicación para procesar Google OAuth 2.0 y determinar si esta se ve afectada. Para ello, usa como referencia la guía que se muestra en los siguientes ejemplos.

Google Identity Services

En el siguiente fragmento de código de la biblioteca JavaScript de Google Identity Services, se inicializa TokenClient con varios permisos que no son de acceso. Se mostrará la pantalla de consentimiento detallado del permiso cuando la app web solicite autorización de los usuarios.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
  https://www.googleapis.com/auth/contacts.readonly',
  callback: (response) => {
    ...
  },
});

Python

En el siguiente fragmento de código, se usa el módulo google-auth-oauthlib.flow para crear la solicitud de autorización. El parámetro scope incluye dos permisos que no son de acceso. Se mostrará la pantalla de consentimiento detallado del permiso cuando la aplicación web solicite autorización de los usuarios.

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/calendar.readonly',
                    'https://www.googleapis.com/auth/contacts.readonly'])

Node.js

El siguiente fragmento de código crea un objeto google.auth.OAuth2, que define los parámetros en la solicitud de autorización cuyo parámetro scope incluye dos permisos que no son de acceso. Se mostrará la pantalla de consentimiento detallado del permiso cuando la app web solicite autorización de los usuarios.

const {google} = require('googleapis');

/**
  * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
  * from the client_secret.json file. To get these credentials for your application, visit
  * https://console.cloud.google.com/apis/credentials.
  */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Calendar and Contacts.
const scopes = [
  'https://www.googleapis.com/auth/calendar.readonly',
  'https://www.googleapis.com/auth/contacts.readonly']
];

// Generate a url that asks permissions
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

Inspeccionar llamada de red saliente

El método para inspeccionar las llamadas de red variará según el tipo de cliente de tu aplicación.

Mientras inspeccionas las llamadas de red, busca las solicitudes enviadas a los extremos de autorización de Google OAuth y examina el parámetro scope.

Estos valores cause que se muestre la pantalla de consentimiento de permisos detallada.

  • El parámetro scope contiene permisos de acceso y otros que no son de acceso.

    La siguiente solicitud de ejemplo contiene los tres permisos de acceso y un permiso que no es de acceso para ver los metadatos de los archivos de Google Drive del usuario:

    https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID
  • El parámetro scope contiene más de un alcance que no es de acceso.

    La siguiente solicitud de ejemplo contiene dos permisos que no son de acceso para ver los metadatos de Google Drive del usuario y administrar archivos específicos de Google Drive:

  • https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID

Prácticas recomendadas para manejar permisos detallados

Si determine que tu aplicación debe actualizarse para administrar permisos detallados, debes realizar las actualizaciones necesarias en tu código a fin de manejar correctamente el consentimiento para varios permisos. Todas las aplicaciones deben cumplir con las siguientes prácticas recomendadas:

  1. Revisa la Política de Datos del Usuario de los Servicios de las APIs de Google y asegúrate de cumplirlas.
  2. Solicita permisos específicos que se necesitan para una tarea. Debes cumplir con la política de Google OAuth 2.0 que indica que solo solicitas los permisos que necesitas. Evita solicitar varios permisos durante el acceso, a menos que sea esencial para la funcionalidad principal de la app. Si agrupas varios permisos, en especial si los usuarios nuevos que no están familiarizados con las funciones de tu aplicación, puede ser difícil para ellos comprender la necesidad de estos permisos. Esto puede generar alarmas y disuadir a los usuarios de continuar interactuando con tu aplicación.
  3. Proporciona una justificación a los usuarios antes de solicitar la autorización. Explica claramente por qué tu aplicación necesita el permiso solicitado, qué harás con los datos del usuario y cómo este se beneficiará al aprobar la solicitud. Nuestra investigación indica que estas explicaciones aumentan la confianza y la participación de los usuarios.
  4. Usa la autorización incremental cada vez que tu aplicación solicite permisos para evitar tener que administrar múltiples tokens de acceso.
  5. Verifica qué permisos otorgaron los usuarios. Si los usuarios solicitan varios permisos a la vez, es posible que no los otorguen todos. Tu app siempre debe verificar qué permisos otorgó el usuario y controlar cualquier denegación de alcances inhabilitando las funciones relevantes. Sigue las políticas de Google OAuth 2.0 sobre cómo manejar el consentimiento para varios permisos y solo vuelve a solicitar el consentimiento del usuario una vez que haya indicado claramente que tiene la intención de usar la función específica que requiere el alcance.

Actualiza tu aplicación para que controle permisos detallados

Aplicaciones para Android

Debes consultar la documentación de los SDK que usas para interactuar con Google OAuth 2.0 y actualizar tu aplicación para que administre permisos detallados según las prácticas recomendadas.

Si usas el SDK auth.api.signin de los Servicios de Play para interactuar con Google OAuth 2.0, puedes usar la función requestPermissions a fin de solicitar el conjunto más pequeño de permisos necesarios y la función hasPermissions para verificar los permisos otorgados por el usuario al solicitar permisos detallados.

Aplicaciones de la extensión de Chrome

Debes usar la API de Chrome Identity para trabajar con Google OAuth 2.0 según las prácticas recomendadas.

En el siguiente ejemplo, se muestra cómo manejar de forma adecuada los permisos detallados.

manifest.json

En el archivo de manifiesto de ejemplo, se declaran dos permisos que no son de acceso para la aplicación de extensión de Chrome.

{
  "name": "Example Chrome extension application",
  ...
  "permissions": [
      "identity"
    ],
  "oauth2" : {
      "client_id": "YOUR_CLIENT_ID",
      "scopes":["https://www.googleapis.com/auth/calendar.readonly",
                "https://www.googleapis.com/auth/contacts.readonly"]
  }
}

Enfoque incorrecto

Todo o nada

Los usuarios hacen clic en el botón para iniciar el proceso de autorización. En el fragmento de código, se supone que a los usuarios se les presenta una pantalla de consentimiento "todo o nada" para los dos permisos especificados en el archivo manifest.json. No verifica qué permisos otorgaron los usuarios.

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken({ interactive: true },
      function (token) {
          if (token === undefined) {
            // User didn't authorize both scopes.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized both or one of the scopes.
            // It neglects to check which scopes users granted and assumes users granted all scopes.

            // Calling the APIs, etc.
            ...
          }
      });
});

Enfoque correcto

Permisos más pequeños

Selecciona el conjunto más pequeño de permisos necesarios

La aplicación solo debe solicitar el conjunto más pequeño de alcances necesarios. Se recomienda que tu aplicación solicite un permiso a la vez cuando sea necesario para completar una tarea.

En este ejemplo, se supone que ambos permisos declarados en el archivo manifest.json son el conjunto más pequeño de permisos necesarios. El archivo oauth.js usa la API de Chrome Identity para iniciar el proceso de autorización con Google. Debes habilitar la opción de habilitar permisos detallados para que los usuarios tengan mayor control cuando otorguen permisos a tu aplicación. Tu aplicación debería controlar correctamente la respuesta de los usuarios. Para ello, verifica qué permisos autorizan.

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken({ interactive: true, enableGranularPermissions: true },
      function (token, grantedScopes) {
          if (token === undefined) {
            // User didn't authorize any scope.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized the request. Now, check which scopes were granted.
            if (grantedScopes.includes('https://www.googleapis.com/auth/calendar.readonly'))
            {
              // User authorized Calendar read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Calendar read permission.
              // Update UX and application accordingly
              ...
            }

            if (grantedScopes.includes('https://www.googleapis.com/auth/contacts.readonly'))
            {
              // User authorized Contacts read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Contacts read permission.
              // Update UX and application accordingly
              ...
            }
          }
      });
});

Aplicaciones para iOS, iPadOS y macOS

Debes consultar la documentación de los SDK que usas para interactuar con Google OAuth 2.0 y actualizar tu aplicación para que administre permisos detallados según las prácticas recomendadas.

Si usas la biblioteca de Acceso con Google para iOS y macOS para interactuar con Google OAuth 2.0, debes revisar la documentación sobre cómo manejar permisos detallados.

Aplicaciones web

Debes consultar la documentación de los SDK que usas para interactuar con Google OAuth 2.0 y actualizar tu aplicación para que administre permisos detallados según las prácticas recomendadas.

Acceso del servidor (sin conexión)

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

En el siguiente fragmento de código, se muestra un ejemplo de Node.js que solicita dos alcances que no son de acceso. Los usuarios verán la pantalla de consentimiento del permiso detallada.

Enfoque incorrecto

Todo o nada

Se redirecciona a los usuarios a la URL de autorización. En el fragmento de código, se supone que a los usuarios se les presenta una pantalla de consentimiento "todo o nada" para los dos permisos especificados en el argumento scopes. No verifica qué permisos otorgaron los usuarios.

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined above
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Example on redirecting user to Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // User authorized both or one of the scopes.
        // It neglects to check which scopes users granted and assumes users granted all scopes.

        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        // Calling the APIs, etc.
        ...
      }
    }
    res.end();
  }).listen(80);
}
Enfoque correcto

Alcance mínimo

Selecciona el conjunto más pequeño de permisos necesarios

La aplicación solo debe solicitar el conjunto más pequeño de alcances necesarios. Se recomienda que tu aplicación solicite un permiso a la vez cuando sea necesario para completar una tarea. Cuando tu aplicación solicite permisos, debe usar la autorización incremental para evitar tener que administrar varios tokens de acceso.

Si tu aplicación debe solicitar varios permisos que no sean de acceso, siempre debes usar la autorización incremental cuando lo solicites y verificar qué permisos otorgaron los usuarios.

En este ejemplo, se supone que los dos permisos indicados son necesarios para que la app funcione correctamente. Debes habilitar la opción de habilitar permisos detallados para que los usuarios tengan mayor control cuando otorguen permisos a tu aplicación. Tu aplicación debería manejar correctamente la respuesta de los usuarios mediante la verificación de los permisos que autorizaron.

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined above
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true,
  // Set to true to enable more granular permissions for Google OAuth 2.0 client IDs created before 2019.
  // No effect for newer Google OAuth 2.0 client IDs, since more granular permissions is always enabled for them.
  enable_granular_consent: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Redirect users to Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        oauth2Client.setCredentials(tokens);

        // User authorized the request. Now, check which scopes were granted.
        if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
        {
          // User authorized Calendar read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Calendar read permission.
          // Calling the APIs, etc.
          ...
        }

        // Check which scopes user granted the permission to application
        if (tokens.scope.includes('https://www.googleapis.com/auth/contacts.readonly'))
        {
          // User authorized Contacts read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Contacts read permission.
          // Update UX and application accordingly
          ...
        }
      }
    }
    res.end();
  }).listen(80);
}

Consulta la guía de aplicaciones web del servidor para acceder a las APIs de Google desde aplicaciones basadas en el servidor.

Acceso de solo cliente

  • En las aplicaciones que usan la biblioteca JavaScript de los servicios de identidad de Google para interactuar con Google OAuth 2.0, debes revisar esta documentación sobre cómo manejar permisos detallados.
  • Para las aplicaciones que realizan llamadas directamente con JavaScript a los extremos de autorización de Google OAuth 2.0, debes revisar esta documentación sobre cómo manejar permisos detallados.

Prueba tu aplicación actualizada sobre el manejo de permisos detallados

  1. Describe todos los casos en los que los usuarios pueden responder a solicitudes de permisos y el comportamiento esperado de tu aplicación. Por ejemplo, si el usuario solo autoriza dos de los tres alcances solicitados, tu aplicación debería comportarse en consecuencia.
  2. Prueba tu aplicación con permisos detallados habilitados. Existen dos maneras de habilitar los permisos detallados:
    1. Revisa las pantallas de consentimiento de OAuth 2.0 de tu aplicación para ver si los permisos detallados ya están habilitados para tu aplicación. También puedes crear un nuevo ID de cliente de Google OAuth 2.0 para la Web, Android o iOS a través de la consola de Google Cloud con fines de prueba, ya que el permiso detallado siempre está habilitado para ellos.
    2. Establece el parámetro enable_granular_consent en true cuando llames a los extremos de autorización de OAuth de Google. Algunos SDK tienen compatibilidad explícita con este parámetro. Para otros, consulta la documentación a fin de ver cómo puedes agregar este parámetro y su valor de forma manual. Si tu implementación no admite agregar el parámetro, puedes crear un nuevo ID de cliente de Google OAuth 2.0 para la Web, Android o iOS a través de la consola de Google Cloud con fines de prueba solo como se indica en el punto anterior.