Como lidar com permissões granulares

Visão geral

Com permissões granulares, os consumidores têm um controle mais refinado sobre quais dados da conta optam por compartilhar com cada app. Eles beneficiam usuários e desenvolvedores, fornecendo maior controle, transparência e segurança. Este guia vai ajudar você a entender as mudanças e etapas necessárias para atualizar seus aplicativos e lidar com permissões granulares.

O que é permissão granular?

Imagine que você desenvolva um app de produtividade que solicite escopos de e-mail e agenda. Talvez os usuários queiram usar o aplicativo apenas para o Google Agenda, mas não para o Gmail. Com permissões do OAuth granulares, os usuários podem optar por conceder permissão apenas ao Google Agenda, não ao Gmail. Ao permitir que os usuários concedam acesso a dados específicos, isso minimiza a exposição de dados, reforça a confiança e oferece aos usuários controle com foco na privacidade sobre a vida digital. É importante projetar seu aplicativo para lidar com esses cenários.

Quando mais de um escopo que não seja de login é solicitado

Escopos de login e não de login

Nos apps que solicitam escopos de login e que não são de login, os usuários primeiro acessam a página de consentimento de escopos de login (email, profile e openid). Depois que os usuários consentirem em compartilhar as informações básicas de identidade (nome, endereço de e-mail e foto do perfil), os usuários verão uma tela de permissão granular para os escopos que não são de login. Nesse caso, o aplicativo precisa verificar quais escopos são concedidos pelos usuários e não pode presumir que os usuários concedem todos os escopos solicitados. No exemplo a seguir, o aplicativo da Web solicita os três escopos de login e um escopo sem login do Google Drive. Depois que os usuários consentirem com os escopos de login, eles verão a tela de permissão granular para a permissão do Google Drive:

Escopos de login e não de login

Mais de um escopo que não seja de login

Uma tela de consentimento de permissão granular é mostrada aos usuários quando os aplicativos solicitam mais de um escopo que não seja de login. Os usuários podem selecionar quais permissões eles querem aprovar para compartilhar com o aplicativo. Confira a seguir um exemplo de tela de permissão granular que solicita acesso às mensagens do Gmail e aos dados do Google Agenda do usuário:

Mais de um escopo que não seja de login

Para aplicativos que solicitam apenas escopos de login (email, profile e openid), a tela de consentimento das permissões #inspect-your-application-codegranular não é relevante. Os usuários aprovam ou negam toda a solicitação de login. Ou seja, se os aplicativos solicitarem apenas escopos de login (um, dois ou todos os três), a tela de permissão granular não será aplicável.

Para aplicativos que solicitam apenas um escopo que não seja de login, a tela de consentimento de permissão granular não será aplicável. Ou seja, os usuários aprovam ou negam toda a solicitação, e não há caixa de seleção na tela de consentimento. A tabela a seguir resume quando a tela de consentimento de permissões granulares é exibida.

Número de escopos de login Número de escopos que não são de login Tela de consentimento de permissões granulares
1-3 0 Não relevante
1-3 + de 1 Aplicável
0 1 Não relevante
0 2+ Aplicável

Determine se seus aplicativos serão afetados

Faça uma análise completa de todas as seções do aplicativo em que os endpoints de autorização do Google OAuth 2.0 são utilizados para solicitações de permissão. Preste atenção naqueles que solicitam vários escopos à medida que eles ativam as telas de consentimento de permissão granular apresentadas aos usuários. Nesses casos, verifique se o código consegue lidar com as situações em que os usuários autorizam apenas alguns dos escopos.

Como determinar se seu aplicativo está usando vários escopos

Inspecione o código do app ou a chamada de rede de saída para determinar se as solicitações de autorização do OAuth 2.0 do Google feitas pelo app farão com que a tela de consentimento de permissões granulares seja mostrada.

Inspecionar o código do aplicativo

Revise as seções do código do aplicativo em que você faz chamadas para os endpoints de autorização do Google OAuth para solicitar a permissão dos usuários. Se você usa uma das bibliotecas de cliente das APIs do Google, geralmente descobre quais escopos o aplicativo solicita nas etapas de inicialização do cliente. Confira alguns exemplos na seção a seguir. Consulte a documentação dos SDKs que seu aplicativo usa para lidar com o Google OAuth 2.0 e determine se seu aplicativo será afetado, usando a orientação mostrada nos exemplos a seguir como referência.

Serviços de Identificação do Google

O snippet de código da biblioteca JavaScript dos Serviços de Identificação do Google a seguir inicializa o TokenClient com vários escopos que não são de login. A tela de consentimento de permissão granular é exibida quando o app da Web solicita a autorização dos usuários.

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

O snippet de código a seguir usa o módulo google-auth-oauthlib.flow para criar a solicitação de autorização. O parâmetro scope inclui dois escopos que não são de login. A tela de consentimento de permissão granular é exibida quando o aplicativo da Web solicita a autorização dos usuários.

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

O snippet de código a seguir cria um objeto google.auth.OAuth2, que define os parâmetros na solicitação de autorização em que o parâmetro scope inclui dois escopos que não são de login. A tela de consentimento de permissão granular será exibida quando o app da Web solicitar a autorização dos usuários.

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
});

Inspecionar chamada de rede de saída

O método para inspecionar chamadas de rede varia de acordo com o tipo de cliente do aplicativo.

Ao inspecionar chamadas de rede, procure solicitações enviadas para os endpoints de autorização do Google OAuth e examine o parâmetro scope.

Esses valores cause a exibição da tela de consentimento granular de permissões.

  • O parâmetro scope contém escopos de login e outros que não.

    O exemplo de solicitação a seguir contém os três escopos de login e um que não seja de login para visualizar os metadados dos arquivos do usuário no Google Drive:

    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
  • O parâmetro scope contém mais de um escopo que não seja de login.

    O exemplo de solicitação a seguir contém dois escopos que não são de login para visualizar os metadados do Google Drive do usuário e gerenciar arquivos específicos do 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áticas recomendadas para lidar com permissões granulares

Se você determine que seu aplicativo precisa ser atualizado para lidar com permissões granulares, faça as atualizações necessárias no código para que ele lide corretamente com o consentimento para vários escopos. Todos os aplicativos precisam obedecer às seguintes práticas recomendadas:

  1. Revise a política de dados do usuário dos serviços das APIs do Google e verifique se você está em conformidade com elas.
  2. Solicite escopos específicos necessários para uma tarefa. É preciso estar em conformidade com a política do Google OAuth 2.0 solicitando apenas os escopos necessários. Evite pedir vários escopos no login, a menos que seja essencial para a funcionalidade principal do app. Agrupá-los, especialmente para novos usuários que não conhecem os recursos do aplicativo, pode dificultar a compreensão da necessidade dessas permissões. Isso pode gerar alarmes e impedir que os usuários interajam mais com seu aplicativo.
  3. Forneça uma justificativa aos usuários antes de fazer a solicitação de autorização. Explique claramente por que seu aplicativo precisa da permissão solicitada, o que você fará com os dados do usuário e como o usuário se beneficiará com a aprovação da solicitação. Nossa pesquisa indica que essas explicações aumentam a confiança e o engajamento do usuário.
  4. Use a autorização incremental sempre que o aplicativo solicitar escopos para evitar o gerenciamento de vários tokens de acesso.
  5. Verifique os escopos concedidos aos usuários. Ao solicitar vários escopos de uma só vez, talvez os usuários não concedam todos os escopos solicitados pelo app. É preciso que seu app sempre verifique quais escopos foram concedidos pelo usuário e desative os recursos relevantes para lidar com qualquer negação de escopo. Siga as políticas do Google OAuth 2.0 sobre gerenciamento de consentimento para vários escopos e só solicite o consentimento do usuário depois que ele indicar claramente uma intenção de usar o recurso específico que exige o escopo.

Atualizar o aplicativo para lidar com permissões granulares

Aplicativos Android

Consulte a documentação dos SDKs que você usa para interagir com o Google OAuth 2.0 e atualize seu aplicativo para lidar com permissões granulares com base nas práticas recomendadas.

Se você usar o SDK auth.api.signin do Google Play Services para interagir com o Google OAuth 2.0, poderá usar a função requestPermissions para solicitar o menor conjunto de escopos necessários e a função hasPermissions para verificar os escopos concedidos pelo usuário ao solicitar permissões granulares.

Aplicativos de extensão do Chrome

Use a API Identity do Chrome para trabalhar com o Google OAuth 2.0 com base nas práticas recomendadas.

O exemplo a seguir mostra como lidar corretamente com permissões granulares.

manifest.json

O arquivo de manifesto de exemplo declara dois escopos que não são de login para o aplicativo de extensão do 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"]
  }
}

Abordagem incorreta

Tudo ou nada

Os usuários clicam no botão para iniciar o processo de autorização. O snippet de código pressupõe que os usuários recebem uma tela de consentimento "tudo ou nada" para os dois escopos especificados no arquivo manifest.json. Ela deixa de verificar quais escopos os usuários concederam.

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.
            ...
          }
      });
});

Abordagem correta

Menor escopo

Selecione o menor conjunto de escopos necessário

O aplicativo deve solicitar apenas o menor conjunto de escopos necessário. Recomenda-se que seu aplicativo solicite um escopo por vez quando for necessário para concluir uma tarefa.

Neste exemplo, supõe-se que ambos os escopos declarados no arquivo manifest.json sejam o menor conjunto necessário. O arquivo oauth.js usa a API Chrome Identity para iniciar o processo de autorização com o Google. É preciso optar por ativar permissões granulares para que os usuários tenham mais controle sobre a concessão de permissões ao aplicativo. Seu aplicativo deve processar corretamente a resposta dos usuários verificando quais escopos eles autorizam.

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
              ...
            }
          }
      });
});

Aplicativos iOS, iPadOS e macOS

Consulte a documentação dos SDKs que você usa para interagir com o Google OAuth 2.0 e atualize seu aplicativo para lidar com permissões granulares com base nas práticas recomendadas.

Se você usa a biblioteca do Login do Google para iOS e macOS para interagir com o OAuth 2.0 do Google, revise a documentação sobre como lidar com permissões granulares.

Aplicativos da Web

Consulte a documentação dos SDKs que você usa para interagir com o Google OAuth 2.0 e atualize seu aplicativo para lidar com permissões granulares com base nas práticas recomendadas.

Acesso do lado do servidor (off-line)

O modo de acesso do lado do servidor (off-line) exige que você faça o seguinte:
  • Coloque um servidor em execução e defina um endpoint acessível publicamente para receber o código de autorização.
  • Configure o URI de redirecionamento do seu endpoint público no Credentials page do console do Google Cloud.

O snippet de código a seguir mostra um exemplo de NodeJS que solicita dois escopos que não são de login. Os usuários vão encontrar a tela de permissão granular.

Abordagem incorreta

Tudo ou nada

Os usuários são redirecionados para o URL de autorização. O snippet de código pressupõe que os usuários recebem uma tela de consentimento "tudo ou nada" para os dois escopos especificados na instrução scopes. Ela deixa de verificar quais escopos os usuários concederam.

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);
}
Abordagem correta

Menor escopo

Selecione o menor conjunto de escopos necessário

O aplicativo deve solicitar apenas o menor conjunto de escopos necessário. Recomenda-se que seu aplicativo solicite um escopo por vez quando for necessário para concluir uma tarefa. Sempre que o aplicativo solicitar escopos, ele deverá usar autorização incremental para evitar a necessidade de gerenciar vários tokens de acesso.

Caso seu aplicativo precise solicitar vários escopos que não sejam de login, use sempre a autorização incremental ao solicitar e verificar quais escopos os usuários concederam.

Neste exemplo, supõe-se que os dois escopos declarados são necessários para o funcionamento correto do app. É preciso optar por ativar permissões granulares para que os usuários tenham mais controle sobre a concessão de permissões ao aplicativo. Seu aplicativo deve processar corretamente a resposta dos usuários verificando quais escopos eles autorizaram.

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);
}

Consulte o guia de apps da Web do lado do servidor para saber como acessar as APIs do Google em aplicativos baseados em servidor.

Acesso apenas no lado do cliente

  • Para que os aplicativos que usam a biblioteca JavaScript dos Serviços de Identificação do Google interajam com o Google OAuth 2.0, confira esta documentação sobre como lidar com permissões granulares.
  • No caso de aplicativos que fazem chamadas diretamente usando JavaScript para endpoints de autorização do Google OAuth 2.0, confira esta documentação sobre como lidar com permissões granulares.

Teste o aplicativo atualizado sobre como lidar com permissões granulares

  1. Descreva todos os casos em que os usuários podem responder a solicitações de permissão e o comportamento esperado do seu aplicativo. Por exemplo, se o usuário autorizar apenas dois dos três escopos solicitados, seu aplicativo deverá se comportar corretamente.
  2. Teste seu aplicativo com a permissão granular ativada. Há duas maneiras de ativar permissões granulares:
    1. Verifique as telas de consentimento do OAuth 2.0 do seu aplicativo para ver se as permissões granulares já estão ativadas. Também é possível criar um novo ID do cliente OAuth 2.0 para Web, Android ou iOS por meio do console do Google Cloud para fins de teste, já que a permissão granular está sempre ativada para eles.
    2. Defina o parâmetro enable_granular_consent como true ao chamar os endpoints de autorização do Google OAuth. Alguns SDKs têm suporte explícito para esse parâmetro. Para outros, consulte a documentação para ver como adicionar esse parâmetro e o valor dele manualmente. Se a sua implementação não oferecer suporte à adição do parâmetro, você poderá criar um novo ID do cliente OAuth 2.0 para Web, Android ou iOS por meio do console do Google Cloud para fins de teste, conforme indicado no ponto anterior.