Migracja do Google Identity Services

Przegląd

Aby uzyskać token dostępu dla każdego użytkownika do wywoływania interfejsów API Google, Google udostępnia kilka bibliotek JavaScript:

Ten przewodnik zawiera instrukcje migracji z tych bibliotek do biblioteki Google Identity Services.

Z tego przewodnika dowiesz się:

  • zastąp przestarzałą bibliotekę Platform Library biblioteką Identity Services,
  • Jeśli używasz biblioteki klienta interfejsu API, usuń przestarzały moduł gapi.auth2, jego metody i obiekty, zastępując je odpowiednikami z usług tożsamości.

Opis zmian w bibliotece JavaScript usług tożsamości znajdziesz w tym artykule. Aby zapoznać się z kluczowymi terminami i pojęciami, przeczytaj też artykuł o tym, jak działa autoryzacja użytkownika.

Jeśli szukasz informacji o uwierzytelnianiu podczas rejestracji i logowania użytkowników, zapoznaj się z artykułem Migracja z Logowania przez Google.

Określanie procesu autoryzacji

Dostępne są 2 przepływy autoryzacji użytkownika: niejawny i kod autoryzacji.

Sprawdź aplikację internetową, aby określić typ używanego procesu autoryzacji.

Sygnały, że aplikacja internetowa korzysta z przepływu niejawnego:

Wskazówki, że aplikacja internetowa używa przepływu kodu autoryzacji:

W niektórych przypadkach baza kodu może obsługiwać oba te procesy.

Wybieranie procesu autoryzacji

Zanim rozpoczniesz migrację, musisz określić, czy kontynuowanie dotychczasowego procesu czy przyjęcie innego procesu najlepiej spełni Twoje potrzeby.

Zapoznaj się z informacjami o wybieraniu procesu autoryzacji, aby poznać kluczowe różnice i kompromisy między tymi dwoma procesami.

W większości przypadków zalecany jest przepływ kodu autoryzacji, ponieważ zapewnia on najwyższy poziom bezpieczeństwa użytkowników. Wdrożenie tego procesu umożliwia też platformie dodawanie nowych funkcji offline, takich jak pobieranie aktualizacji, aby powiadamiać użytkowników o istotnych zmianach w kalendarzu, zdjęciach i subskrypcjach.

Wybierz przepływ autoryzacji za pomocą selektorów.

Przepływ niejawny

Uzyskaj token dostępu do użycia w przeglądarce, gdy użytkownik jest obecny.

W sekcji Przykłady przepływu niejawnego pokazujemy aplikacje internetowe przed migracją do usług tożsamości i po niej.

Przepływ kodu autoryzacji

Kod autoryzacji wydany przez Google dla każdego użytkownika jest dostarczany na platformę backendu, gdzie jest wymieniany na token dostępu i token odświeżania.

Przykłady przepływu kodu autoryzacji pokazują aplikacje internetowe przed migracją do usług tożsamości i po niej.

W tym przewodniku postępuj zgodnie z instrukcjami podanymi pogrubioną czcionką, aby dodać, usunąć, zaktualizować lub zastąpić istniejące funkcje.

Zmiany w aplikacji internetowej w przeglądarce

W tej sekcji opisujemy zmiany, które wprowadzisz w aplikacji internetowej w przeglądarce podczas migracji do biblioteki JavaScript Google Identity Services.

Identyfikowanie kodu, którego dotyczy problem, i przeprowadzanie testów

Plik cookie debugowania może pomóc w zlokalizowaniu kodu, którego dotyczy problem, i w testowaniu działania po wycofaniu funkcji.

W przypadku dużych lub złożonych aplikacji znalezienie całego kodu, na który wpłynie wycofanie modułu gapi.auth2, może być trudne. Aby rejestrować w konsoli dotychczasowe użycie funkcji, które wkrótce zostaną wycofane, ustaw wartość pliku cookie G_AUTH2_MIGRATION na informational. Opcjonalnie możesz dodać dwukropek, a po nim wartość klucza, aby rejestrować dane również w pamięci sesji. Po zalogowaniu i otrzymaniu danych logowania sprawdź lub wyślij zebrane logi do backendu w celu późniejszej analizy. Na przykład informational:showauth2use zapisuje pochodzenie i adres URL w kluczu pamięci sesji o nazwie showauth2use.

Aby sprawdzić działanie aplikacji, gdy moduł gapi.auth2 nie jest już wczytywany, ustaw wartość pliku cookie G_AUTH2_MIGRATION na enforced. Umożliwia to testowanie zachowania po wycofaniu funkcji przed datą wejścia w życie zmian.

Możliwe wartości plików cookie G_AUTH2_MIGRATION:

  • enforced Nie wczytuj modułu gapi.auth2.
  • informational Rejestruj użycie wycofanych funkcji w konsoli JS. Gdy ustawiona jest opcjonalna nazwa klucza, zapisz też dane w pamięci sesji:informational:key-name

Aby zminimalizować wpływ na użytkowników, zalecamy najpierw ustawić ten plik cookie lokalnie podczas programowania i testowania, a dopiero potem używać go w środowiskach produkcyjnych.

Biblioteki i moduły

Moduł gapi.auth2 zarządza uwierzytelnianiem użytkowników podczas logowania oraz niejawnym przepływem autoryzacji. Zastąp ten wycofany moduł, jego obiekty i metody biblioteką Google Identity Services.

Dodaj bibliotekę Identity Services do aplikacji internetowej, umieszczając ją w dokumencie:

<script src="https://accounts.google.com/gsi/client" async defer></script>

Usuń wszystkie wystąpienia wczytywania modułu auth2 za pomocą gapi.load('auth2', function).

Biblioteka Google Identity Services zastępuje moduł gapi.auth2. Możesz bezpiecznie nadal używać modułu gapi.clientGoogle API Client Library for JavaScript i korzystać z jego funkcji automatycznego tworzenia wywoływalnych metod JS na podstawie dokumentu discovery, łączenia wielu wywołań interfejsu API w pakiety i zarządzania CORS.

Pliki cookie

Autoryzacja użytkownika nie wymaga używania plików cookie.

Więcej informacji o tym, jak uwierzytelnianie użytkowników korzysta z plików cookie, znajdziesz w artykule Przechodzenie z usługi Zaloguj się przez Google, a o tym, jak z plików cookie korzystają inne usługi Google, dowiesz się z artykułu Jak Google korzysta z plików cookie.

Dane logowania

Usługi tożsamości Google rozdzielają uwierzytelnianie i autoryzację użytkownika na 2 oddzielne operacje, a dane logowania użytkownika są oddzielne: token identyfikatora używany do identyfikowania użytkownika jest zwracany oddzielnie od tokena dostępu używanego do autoryzacji.

Aby zobaczyć te zmiany, zapoznaj się z przykładem danych logowania.

Przepływ niejawny

Oddzielenie uwierzytelniania i autoryzacji użytkownika przez usunięcie obsługi profilu użytkownika z procesów autoryzacji.

Usuń te odwołania do klienta JavaScriptu Google Sign-In:

Metody

  • GoogleUser.getBasicProfile()
  • GoogleUser.getId()

Przepływ kodu autoryzacji

Usługi dotyczące tożsamości rozdzielają dane logowania w przeglądarce na token tożsamości i token dostępu. Ta zmiana nie dotyczy danych logowania uzyskanych w wyniku bezpośrednich wywołań punktów końcowych Google OAuth 2.0 z platformy backendu ani za pomocą bibliotek działających na bezpiecznym serwerze na Twojej platformie, takich jak klient Google API na Node.js.

Stan sesji

Wcześniej logowanie przez Google pomagało zarządzać stanem zalogowania użytkownika za pomocą tych metod:

Odpowiadasz za zarządzanie stanem logowania i sesjami użytkowników w swojej aplikacji internetowej.

Usuń te odwołania do klienta JavaScriptu Google Sign-In:

Obiekty:

  • gapi.auth2.SignInOptions

Metody:

  • GoogleAuth.attachClickHandler()
  • GoogleAuth.isSignedIn()
  • GoogleAuth.isSignedIn.get()
  • GoogleAuth.isSignedIn.listen()
  • GoogleAuth.signIn()
  • GoogleAuth.signOut()
  • GoogleAuth.currentUser.get()
  • GoogleAuth.currentUser.listen()
  • GoogleUser.isSignedIn()

Konfiguracja klienta

Zaktualizuj aplikację internetową, aby zainicjować klienta tokena w przypadku przepływu niejawnego lub przepływu kodu autoryzacji.

Usuń te odwołania do klienta JavaScriptu Google Sign-In:

Obiekty:

  • gapi.auth2.ClientConfig
  • gapi.auth2.OfflineAccessOptions

Metody:

  • gapi.auth2.getAuthInstance()
  • GoogleUser.grant()

Przepływ niejawny

Dodaj obiekt TokenClientConfig i wywołaj initTokenClient() funkcję, aby skonfigurować aplikację internetową, korzystając z przykładu w sekcji Inicjowanie klienta tokena.

Zastąp odwołania do klienta JavaScriptu do logowania przez Google Google Identity Services:

Obiekty:

  • gapi.auth2.AuthorizeConfigTokenClientConfig

Metody:

  • gapi.auth2.init()google.accounts.oauth2.initTokenClient()

Parametry:

  • gapi.auth2.AuthorizeConfig.login_hint z TokenClientConfig.login_hint.
  • gapi.auth2.GoogleUser.getHostedDomain() z TokenClientConfig.hd.

Przepływ kodu autoryzacji

Dodaj obiekt CodeClientConfig i wywołanie initCodeClient(), aby skonfigurować aplikację internetową, zgodnie z przykładem w artykule inicjowanie klienta kodu.

Podczas przechodzenia z procesu pośredniego na proces kodu autoryzacji:

Usuń odniesienia do klienta JavaScript usługi Logowanie przez Google

Obiekty:

  • gapi.auth2.AuthorizeConfig

Metody:

  • gapi.auth2.init()

Parametry:

  • gapi.auth2.AuthorizeConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain()

Żądanie tokena

Gest użytkownika, np. kliknięcie przycisku, generuje żądanie, w wyniku którego token dostępu jest zwracany bezpośrednio do przeglądarki użytkownika w ramach przepływu niejawnego lub do Twojej platformy backendowej po wymianie kodu autoryzacji użytkownika na token dostępu i token odświeżania.

Przepływ niejawny

Tokeny dostępu można uzyskiwać i używać w przeglądarce, gdy użytkownik jest zalogowany i ma aktywną sesję w Google. W trybie niejawnym do wysłania prośby o token dostępu wymagany jest gest użytkownika, nawet jeśli wcześniej wysłano już prośbę.

Zastąp odwołania do klienta JavaScriptu Google Sign-In Google Identity Services:

Metody:

  • gapi.auth2.authorize()TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() z oferty TokenClient.requestAccessToken()

Dodaj link lub przycisk, aby wywołać requestAccessToken() i rozpocząć proces UX w wyskakującym okienku, który umożliwia wysłanie prośby o token dostępu lub uzyskanie nowego tokena, gdy dotychczasowy wygaśnie.

Zaktualizuj bazę kodu, aby:

  • Uruchom przepływ tokena OAuth 2.0 za pomocą requestAccessToken().
  • Obsługa autoryzacji przyrostowej za pomocą znaków requestAccessTokenOverridableTokenClientConfig, które umożliwiają podzielenie jednego żądania dotyczącego wielu zakresów na kilka mniejszych żądań.
  • Gdy obecny token wygaśnie lub zostanie unieważniony, poproś o nowy.

Praca z wieloma zakresami może wymagać zmian strukturalnych w kodzie, aby żądać dostępu do zakresów tylko wtedy, gdy są potrzebne, a nie wszystkich naraz. Jest to tak zwana autoryzacja przyrostowa. Każde żądanie powinno zawierać jak najmniej zakresów, a najlepiej tylko jeden. Więcej informacji o tym, jak zaktualizować aplikację pod kątem autoryzacji przyrostowej, znajdziesz w artykule Jak uzyskać zgodę użytkownika.

Gdy token dostępu wygaśnie, moduł gapi.auth2 automatycznie pobiera nowy, ważny token dostępu dla Twojej aplikacji internetowej. Aby zwiększyć bezpieczeństwo użytkowników, biblioteka usług Google Identity nie obsługuje tego automatycznego odświeżania tokena. Aplikacja internetowa musi być zaktualizowana, aby wykrywać wygasłe tokeny dostępu i wysyłać prośby o nowe. Więcej informacji znajdziesz w sekcji Obsługa tokenów.

Przepływ kodu autoryzacji

Dodaj link lub przycisk, aby wywołać requestCode() i poprosić Google o kod autoryzacji. Przykład znajdziesz w artykule Uruchamianie przepływu kodu OAuth 2.0.

Więcej informacji o tym, jak reagować na wygasły lub unieważniony token dostępu, znajdziesz w sekcji Obsługa tokenów.

Obsługa tokenów

Dodaj obsługę błędów, aby wykrywać nieudane wywołania interfejsu API Google w przypadku użycia wygasłego lub unieważnionego tokena dostępu, i aby wysyłać prośby o nowy, prawidłowy token dostępu.

Interfejsy API Google zwracają kod stanu HTTP 401 Unauthorized i komunikat o błędzie invalid_token, gdy używany jest wygasły lub unieważniony token dostępu. Przykład znajdziesz w sekcji Nieprawidłowa odpowiedź tokena.

Wygasłe tokeny

Tokeny dostępu są krótkotrwałe i często ważne tylko przez kilka minut.

Unieważnienie tokena

Właściciel konta Google może w każdej chwili wycofać wcześniej udzieloną zgodę. Spowoduje to unieważnienie dotychczasowych tokenów dostępu i tokenów odświeżania. Cofnięcie może zostać zainicjowane na Twojej platformie za pomocą revoke() lub za pośrednictwem konta Google.

Zastąp odwołania do klienta JavaScriptu Google Sign-In Google Identity Services:

Metody:

  • getAuthInstance().disconnect()google.accounts.oauth2.revoke()
  • GoogleUser.disconnect()google.accounts.oauth2.revoke()

Wywołuj funkcję revoke, gdy użytkownik usunie swoje konto na Twojej platformie lub wycofa zgodę na udostępnianie danych Twojej aplikacji.

Gdy aplikacja internetowa lub platforma backendu zażąda tokena dostępu, Google wyświetli użytkownikowi okno z prośbą o zgodę. Zobacz przykładowe okna z prośbą o zgodę wyświetlane przez Google użytkownikom.

Zanim aplikacja otrzyma token dostępu, musi istnieć aktywna sesja Google, która wyświetli prośbę o zgodę użytkownika i zarejestruje wynik. Użytkownik może być poproszony o zalogowanie się na konto Google, jeśli nie ma jeszcze aktywnej sesji.

Logowanie użytkownika

Użytkownicy mogą być zalogowani na konto Google na osobnej karcie przeglądarki lub natywnie w przeglądarce lub systemie operacyjnym. Zalecamy dodanie do witryny opcji Zaloguj się za pomocą Google, aby przy pierwszym otwarciu aplikacji przez użytkownika nawiązać aktywną sesję między kontem Google a przeglądarką. Przyniesie to następujące korzyści:

  • Minimalizuje liczbę logowań użytkownika. Jeśli nie ma aktywnej sesji, żądanie tokena dostępu inicjuje proces logowania na konto Google.
  • Użyj bezpośrednio pola credential tokena identyfikatora JWT email jako wartości parametru login_hint w obiektach CodeClientConfig lub TokenClientConfig. Jest to szczególnie przydatne, jeśli Twoja platforma nie ma systemu zarządzania kontami użytkowników.
  • Wyszukiwanie i powiązywanie konta Google z istniejącym lokalnym kontem użytkownika na Twojej platformie, co pomaga zminimalizować liczbę zduplikowanych kont na platformie.
  • Gdy tworzone jest nowe konto lokalne, okna i proces rejestracji mogą być wyraźnie oddzielone od okien i procesu uwierzytelniania użytkownika, co zmniejsza liczbę wymaganych kroków i poprawia współczynnik rezygnacji.

Po zalogowaniu się i zanim zostanie wydany token dostępu, użytkownicy muszą wyrazić zgodę na zakresy żądane przez aplikację.

Po wyrażeniu zgody zwracany jest token dostępu wraz z listą zakresów zatwierdzonych lub odrzuconych przez użytkownika.

Szczegółowe uprawnienia pozwalają użytkownikom zatwierdzać lub odrzucać poszczególne zakresy. Gdy prosisz o dostęp do wielu zakresów, każdy z nich jest przyznawany lub odrzucany niezależnie od pozostałych. W zależności od wyboru użytkownika aplikacja selektywnie włącza funkcje, które zależą od indywidualnego zakresu.

Przepływ niejawny

Zastąp odwołania do klienta JavaScriptu do logowania przez Google Google Identity Services:

Obiekty:

  • gapi.auth2.AuthorizeResponseTokenClient.TokenResponse
  • gapi.auth2.AuthResponseTokenClient.TokenResponse

Metody:

  • GoogleUser.hasGrantedScopes() z oferty google.accounts.oauth2.hasGrantedAllScopes()
  • GoogleUser.getGrantedScopes() z oferty google.accounts.oauth2.hasGrantedAllScopes()

Usuń odwołania do klienta JavaScriptu do logowania przez Google:

Metody:

  • GoogleUser.getAuthResponse()

Zaktualizuj aplikację internetową za pomocą hasGrantedAllScopes()hasGrantedAnyScope(), korzystając z tego przykładu szczegółowych uprawnień.

Przepływ kodu autoryzacji

Zaktualizuj lub dodaj punkt końcowy kodu autoryzacji do platformy backendu, postępując zgodnie z instrukcjami w sekcji Obsługa kodu autoryzacji.

Zaktualizuj platformę, aby wykonać czynności opisane w przewodniku Korzystanie z modelu kodu. Dzięki temu zweryfikujesz żądanie i uzyskasz token dostępu oraz token odświeżania.

Zaktualizuj platformę, aby selektywnie włączać lub wyłączać funkcje na podstawie poszczególnych zakresów zatwierdzonych przez użytkownika. W tym celu postępuj zgodnie z instrukcjami dotyczącymi autoryzacji przyrostowej i sprawdź zakresy dostępu przyznane przez użytkownika.

Przykłady przepływu niejawnego

Stary sposób

Biblioteka klienta GAPI

Przykład działania biblioteki klienta interfejsu API Google w JavaScript w przeglądarce z użyciem wyskakującego okna dialogowego do uzyskiwania zgody użytkownika.

Moduł gapi.auth2 jest automatycznie wczytywany i używany przez gapi.client.init(), dlatego jest ukryty.

<!DOCTYPE html>
  <html>
    <head>
      <script src="https://apis.google.com/js/api.js"></script>
      <script>
        function start() {
          gapi.client.init({
            'apiKey': 'YOUR_API_KEY',
            'clientId': 'YOUR_CLIENT_ID',
            'scope': 'https://www.googleapis.com/auth/cloud-translation',
            'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
          }).then(function() {
            // Execute an API request which is returned as a Promise.
            // The method name language.translations.list comes from the API discovery.
            return gapi.client.language.translations.list({
              q: 'hello world',
              source: 'en',
              target: 'de',
            });
          }).then(function(response) {
            console.log(response.result.data.translations[0].translatedText);
          }, function(reason) {
            console.log('Error: ' + reason.result.error.message);
          });
        };

        // Load the JavaScript client library and invoke start afterwards.
        gapi.load('client', start);
      </script>
    </head>
    <body>
      <div id="results"></div>
    </body>
  </html>

Biblioteka klienta JS

OAuth 2.0 w przypadku aplikacji internetowych po stronie klienta działający w przeglądarce, który do uzyskiwania zgody użytkownika używa okna wyskakującego.

Moduł gapi.auth2 jest wczytywany ręcznie.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from Google Cloud console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus() {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>

Punkty końcowe OAuth 2.0

OAuth 2.0 w przypadku aplikacji internetowych działających po stronie klienta, które działają w przeglądarce i używają przekierowań do Google w celu uzyskania zgody użytkownika.

Ten przykład pokazuje bezpośrednie wywołania punktów końcowych OAuth 2.0 Google z przeglądarki użytkownika. Nie korzysta z modułu gapi.auth2 ani biblioteki JavaScript.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);

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

  // 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']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          '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 {
      oauth2SignIn();
    }
  }

  /*

    *   Create form to request access token from Google's OAuth 2.0 server.
 */
function oauth2SignIn() {
  // 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/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  '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>

Nowy sposób

Tylko GIS

Ten przykład pokazuje tylko bibliotekę JavaScript usługi Google Identity Service korzystającą z modelu tokena i okna wyskakującego do uzyskiwania zgody użytkownika. Jest on podany, aby zilustrować minimalną liczbę kroków wymaganych do skonfigurowania klienta, wysłania żądania i uzyskania tokena dostępu oraz wywołania interfejsu API Google.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;

      function initClient() {
        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: (tokenResponse) => {
            access_token = tokenResponse.access_token;
          },
        });
      }
      function getToken() {
        client.requestAccessToken();
      }
      function revokeToken() {
        google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
      }
      function loadCalendar() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
        xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        xhr.send();
      }
    </script>
    <h1>Google Identity Services Authorization Token model</h1>
    <button onclick="getToken();">Get access token</button><br><br>
    <button onclick="loadCalendar();">Load Calendar</button><br><br>
    <button onclick="revokeToken();">Revoke token</button>
  </body>
</html>

GAPI async/await

W tym przykładzie pokazujemy, jak dodać bibliotekę Google Identity Service za pomocą modelu tokena, usunąć moduł gapi.auth2 i wywołać interfejs API za pomocą biblioteki klienta interfejsu API Google dla JavaScriptu.

Obietnice, funkcje asynchroniczne i await są używane do wymuszania kolejności ładowania biblioteki oraz do wykrywania błędów autoryzacji i ponawiania prób. Wywołanie interfejsu API następuje tylko wtedy, gdy dostępny jest prawidłowy token dostępu.

Użytkownicy powinni kliknąć przycisk „Pokaż kalendarz”, gdy token dostępu jest niedostępny przy pierwszym wczytaniu strony lub później, po wygaśnięciu tokena dostępu.

<!DOCTYPE html>
<html>
<head>
    <title>GAPI and GIS Example</title>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoad()"></script>
</head>
<body>
    <h1>GAPI Client with GIS Authorization</h1>
    <button id="authorizeBtn" style="visibility:hidden;">Authorize and Load Events</button>
    <button id="revokeBtn" style="visibility:hidden;">Revoke Access</button>
    <div id="content"></div>

    <script>
        const YOUR_CLIENT_ID = "YOUR_CLIENT_ID";
        const YOUR_API_KEY = 'YOUR_API_KEY';
        const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';

        let tokenClient;
        let libsLoaded = 0;

        function gapiLoad() {
            gapi.load('client', initGapiClient);
        }

        async function initGapiClient() {
            try {
                await gapi.client.init({ apiKey: YOUR_API_KEY });
                await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
                console.log('GAPI client initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GAPI initialization failed:', err);
            }
        }

        function gisLoad() {
            try {
                tokenClient = google.accounts.oauth2.initTokenClient({
                    client_id: YOUR_CLIENT_ID,
                    scope: CALENDAR_SCOPE,
                    callback: '', // Will be set dynamically
                    error_callback: handleGisError,
                });
                console.log('GIS TokenClient initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GIS initialization failed:', err);
            }
        }

        function checkAllLoaded() {
            libsLoaded++;
            if (libsLoaded === 2) {
                document.getElementById('authorizeBtn').style.visibility = 'visible';
                document.getElementById('revokeBtn').style.visibility = 'visible';
                document.getElementById('authorizeBtn').onclick = makeApiCall;
                document.getElementById('revokeBtn').onclick = revokeAccess;
                console.log('Ready to authorize.');
            }
        }

        function handleGisError(err) {
            console.error('GIS Error:', err);
            let message = 'An error occurred during authorization.';
            if (err && err.type === 'popup_failed_to_open') {
                message = 'Failed to open popup. Please disable popup blockers.';
            } else if (err && err.type === 'popup_closed') {
                message = 'Authorization popup was closed.';
            }
            document.getElementById('content').textContent = message;
        }

        function handleError(message, error) {
            console.error(message, error);
            document.getElementById('content').textContent = `${message} ${error.message || JSON.stringify(error)}`;
        }

        async function makeApiCall() {
            document.getElementById('content').textContent = 'Processing...';
            try {
                let token = gapi.client.getToken();
                if (!token || !token.access_token) {
                    console.log('No token, fetching one...');
                    await getToken();
                }

                console.log('Calling Calendar API...');
                const response = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                displayEvents(response.result);
            } catch (err) {
                console.error('API call failed:', err);
                const errorInfo = err.result && err.result.error;
                if (errorInfo && (errorInfo.code === 401 || (errorInfo.code === 403 && errorInfo.status === "PERMISSION_DENIED"))) {
                    console.log('Auth error on API call, refreshing token...');
                    try {
                        await getToken({ prompt: 'consent' }); // Force refresh
                        const retryResponse = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                        displayEvents(retryResponse.result);
                    } catch (refreshErr) {
                        handleError('Failed to refresh token or retry API call:', refreshErr);
                    }
                } else {
                    handleError('Error loading events:', err.result ? err.result.error : err);
                }
            }
        }

        async function getToken(options = { prompt: '' }) {
            return new Promise((resolve, reject) => {
                if (!tokenClient) return reject(new Error("GIS TokenClient not initialized."));
                tokenClient.callback = (tokenResponse) => {
                    if (tokenResponse.error) {
                        reject(new Error(`Token Error: ${tokenResponse.error} - ${tokenResponse.error_description}`));
                    } else {
                        console.log('Token acquired.');
                        resolve(tokenResponse);
                    }
                };
                tokenClient.requestAccessToken(options);
            });
        }

        function displayEvents(result) {
            const events = result.items;
            if (events && events.length > 0) {
                let eventList = '<h3>Upcoming Events:</h3><ul>' + events.map(event =>
                    `<li>${event.summary} (${event.start.dateTime || event.start.date})</li>`
                ).join('') + '</ul>';
                document.getElementById('content').innerHTML = eventList;
            } else {
                document.getElementById('content').textContent = 'No upcoming events found.';
            }
        }

        function revokeAccess() {
            const token = gapi.client.getToken();
            if (token && token.access_token) {
                google.accounts.oauth2.revoke(token.access_token, () => {
                    console.log('Access revoked.');
                    document.getElementById('content').textContent = 'Access has been revoked.';
                    gapi.client.setToken(null);
                });
            } else {
                document.getElementById('content').textContent = 'No token to revoke.';
            }
        }
    </script>
</body>
</html>

Wywołanie zwrotne GAPI

W tym przykładzie pokazujemy, jak dodać bibliotekę Google Identity Service za pomocą modelu tokena, usunąć moduł gapi.auth2 i wywołać interfejs API za pomocą biblioteki klienta interfejsu API Google dla JavaScriptu.

Zmienne służą do wymuszania kolejności wczytywania biblioteki. Wywołania GAPI są wykonywane w funkcji zwrotnej po zwróceniu prawidłowego tokena dostępu.

Użytkownicy powinni nacisnąć przycisk Pokaż kalendarz po pierwszym załadowaniu strony i ponownie, gdy chcą odświeżyć informacje w kalendarzu.

<!DOCTYPE html>
<html>
<head>
  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
  <h1>GAPI with GIS callbacks</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
  <script>
    let tokenClient;
    let gapiInited;
    let gisInited;

    document.getElementById("showEventsBtn").style.visibility="hidden";
    document.getElementById("revokeBtn").style.visibility="hidden";

    function checkBeforeStart() {
       if (gapiInited && gisInited){
          // Start only when both gapi and gis are initialized.
          document.getElementById("showEventsBtn").style.visibility="visible";
          document.getElementById("revokeBtn").style.visibility="visible";
       }
    }

    function gapiInit() {
      gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
        gapiInited = true;
        checkBeforeStart();
      });
    }

    function gapiLoad() {
        gapi.load('client', gapiInit)
    }

    function gisInit() {
     tokenClient = google.accounts.oauth2.initTokenClient({
                client_id: 'YOUR_CLIENT_ID',
                scope: 'https://www.googleapis.com/auth/calendar.readonly',
                callback: '',  // defined at request time
            });
      gisInited = true;
      checkBeforeStart();
    }

    function showEvents() {

      tokenClient.callback = (resp) => {
        if (resp.error !== undefined) {
          throw(resp);
        }
        // GIS has automatically updated gapi.client with the newly issued access token.
        console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));

        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
        .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
        .catch(err => console.log(err));

        document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
      }

      // Conditionally ask users to select the Google Account they'd like to use,
      // and explicitly obtain their consent to fetch their Calendar.
      // NOTE: To request an access token a user gesture is necessary.
      if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and asked for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({prompt: 'consent'});
      } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({prompt: ''});
      }
    }

    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
        document.getElementById("showEventsBtn").innerText = "Show Calendar";
      }
    }
  </script>
</body>
</html>

Przykłady przepływu kodu autoryzacji

Wyskakujące okienko biblioteki Google Identity Service może używać przekierowania URL, aby zwrócić kod autoryzacji bezpośrednio do punktu końcowego tokena backendu, lub wywołania zwrotnego JavaScript działającego w przeglądarce użytkownika, które przekazuje odpowiedź do Twojej platformy. W obu przypadkach platforma backendu dokończy przepływ OAuth 2.0, aby uzyskać prawidłowy token odświeżania i token dostępu.

Stary sposób

Aplikacje internetowe po stronie serwera

Logowanie przez Google w przypadku aplikacji po stronie serwera działających na platformie backendowej z użyciem przekierowania do Google w celu uzyskania zgody użytkownika.

<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
    <script>
      function start() {
        gapi.load('auth2', function() {
          auth2 = gapi.auth2.init({
            client_id: 'YOUR_CLIENT_ID',
            api_key: 'YOUR_API_KEY',
            discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
            // Scopes to request in addition to 'profile' and 'email'
            scope: 'https://www.googleapis.com/auth/cloud-translation',
          });
        });
      }
      function signInCallback(authResult) {
        if (authResult['code']) {
          console.log("sending AJAX request");
          // Send authorization code obtained from Google to backend platform
          $.ajax({
            type: 'POST',
            url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
            // Always include an X-Requested-With header to protect against CSRF attacks.
            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              console.log(result);
            },
            processData: false,
            data: authResult['code']
          });
        } else {
          console.log('error: failed to obtain authorization code')
        }
      }
    </script>
  </head>
  <body>
    <button id="signinButton">Sign In With Google</button>
    <script>
      $('#signinButton').click(function() {
        // Obtain an authorization code from Google
        auth2.grantOfflineAccess().then(signInCallback);
      });
    </script>
  </body>
</html>

HTTP/REST z użyciem przekierowania

Użyj OAuth 2.0 w aplikacjach udostępnianych przez serwer WWW, aby wysłać kod autoryzacji z przeglądarki użytkownika na platformę backendu. Zgoda użytkownika jest uzyskiwana przez przekierowanie przeglądarki użytkownika do Google.

/\*
 \* 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 &lt;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_AUTHORIZATION_CODE_ENDPOINT_URL',
                'response\_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.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();
}

Nowy sposób

GIS Popup UX

Ten przykład pokazuje tylko bibliotekę JavaScript Google Identity Service korzystającą z modelu kodu autoryzacji, okno wyskakujące do uzyskiwania zgody użytkownika oraz procedurę obsługi wywołania zwrotnego do odbierania kodu autoryzacji od Google. Ma on na celu zilustrowanie minimalnej liczby kroków wymaganych do skonfigurowania klienta, uzyskania zgody użytkownika i wysłania kodu autoryzacji do platformy backendowej.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly',
          ux_mode: 'popup',
          callback: (response) => {
            var code_receiver_uri = 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI',
            // Send auth code to your backend platform
            const xhr = new XMLHttpRequest();
            xhr.open('POST', code_receiver_uri, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.onload = function() {
              console.log('Signed in as: ' + xhr.responseText);
            };
            xhr.send('code=' + response.code);
            // After receipt, the code is exchanged for an access token and
            // refresh token, and the platform then updates this web app
            // running in user's browser with the requested calendar info.
          },
        });
      }
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

GIS Redirect UX

Model kodu autoryzacji obsługuje tryby UX wyskakującego okienka i przekierowania, aby wysyłać kod autoryzacji dla każdego użytkownika do punktu końcowego hostowanego przez Twoją platformę. Tryb UX przekierowania jest widoczny tutaj:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/photoslibrary.readonly',
          ux_mode: 'redirect',
          redirect_uri: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI'
        });
      }
      // Request an access token
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

Biblioteki JavaScript

Usługi Google Identity Services to jedna biblioteka JavaScriptu używana do uwierzytelniania i autoryzacji użytkowników, która konsoliduje i zastępuje funkcje i funkcjonalności znajdujące się w wielu różnych bibliotekach i modułach:

Działania, które należy wykonać podczas migracji do usług tożsamości:

Istniejąca biblioteka JS Nowa biblioteka JS Uwagi
apis.google.com/js/api.js accounts.google.com/gsi/client Dodaj nową bibliotekę i postępuj zgodnie z przepływem niejawnym.
apis.google.com/js/client.js accounts.google.com/gsi/client Dodaj nową bibliotekę i przepływ kodu autoryzacji.

Krótkie omówienie biblioteki

Porównanie obiektów i metod w starej bibliotece Google Sign-In JavaScriptnowej bibliotece Google Identity Services oraz uwagi z dodatkowymi informacjami i działaniami, które należy podjąć podczas migracji.

Stary Nowy Uwagi
Obiekt GoogleAuth i powiązane z nim metody:
GoogleAuth.attachClickHandler() Usuń
GoogleAuth.currentUser.get() Usuń
GoogleAuth.currentUser.listen() Usuń
GoogleAuth.disconnect() google.accounts.oauth2.revoke Zastąp stary nowym. Cofnięcie może też nastąpić na stronie https://myaccount.google.com/permissions.
GoogleAuth.grantOfflineAccess() Usuń, postępując zgodnie z przepływem kodu autoryzacji.
GoogleAuth.isSignedIn.get() Usuń
GoogleAuth.isSignedIn.listen() Usuń
GoogleAuth.signIn() Usuń
GoogleAuth.signOut() Usuń
GoogleAuth.then() Usuń
Obiekt GoogleUser i powiązane z nim metody:
GoogleUser.disconnect() google.accounts.id.revoke Zastąp stary nowym. Cofnięcie może też nastąpić na stronie https://myaccount.google.com/permissions.
GoogleUser.getAuthResponse() requestCode() or requestAccessToken() Zastąpienie starego nowym
GoogleUser.getBasicProfile() Usuń. Zamiast niego używaj tokena tożsamości. Więcej informacji znajdziesz w artykule Migracja z logowania przez Google.
GoogleUser.getGrantedScopes() hasGrantedAnyScope() Zastąpienie starego nowym
GoogleUser.getHostedDomain() Usuń
GoogleUser.getId() Usuń
GoogleUser.grantOfflineAccess() Usuń, postępując zgodnie z przepływem kodu autoryzacji.
GoogleUser.grant() Usuń
GoogleUser.hasGrantedScopes() hasGrantedAnyScope() Zastąpienie starego nowym
GoogleUser.isSignedIn() Usuń
GoogleUser.reloadAuthResponse() requestAccessToken() Usuń stary token dostępu i wywołaj nowy, aby zastąpić wygasły lub unieważniony token dostępu.
Obiekt gapi.auth2 i powiązane z nim metody:
Obiekt gapi.auth2.AuthorizeConfig TokenClientConfig lub CodeClientConfig Zastąpienie starego nowym
Obiekt gapi.auth2.AuthorizeResponse Usuń
Obiekt gapi.auth2.AuthResponse Usuń
gapi.auth2.authorize() requestCode() or requestAccessToken() Zastąpienie starego nowym
gapi.auth2.ClientConfig() TokenClientConfig lub CodeClientConfig Zastąpienie starego nowym
gapi.auth2.getAuthInstance() Usuń
gapi.auth2.init() initTokenClient() or initCodeClient() Zastąpienie starego nowym
Obiekt gapi.auth2.OfflineAccessOptions Usuń
Obiekt gapi.auth2.SignInOptions Usuń
Obiekt gapi.signin2 i powiązane z nim metody:
gapi.signin2.render() Usuń. Wczytanie elementu g_id_signin w HTML DOM lub wywołanie JS funkcji google.accounts.id.renderButton powoduje zalogowanie użytkownika na konto Google.

Przykładowe dane logowania

Istniejące dane logowania

Biblioteka platformy Logowanie przez Google, biblioteka klienta interfejsu API Google dla JavaScriptu lub bezpośrednie wywołania punktów końcowych Google OAuth 2.0 zwracają w jednej odpowiedzi token dostępu OAuth 2.0 i token identyfikatora OpenID Connect.

Przykładowa odpowiedź zawierająca zarówno access_token, jak i id_token:

  {
    "token_type": "Bearer",
    "access_token": "ya29.A0ARrdaM-SmArZaCIh68qXsZSzyeU-8mxhQERHrP2EXtxpUuZ-3oW8IW7a6D2J6lRnZrRj8S6-ZcIl5XVEqnqxq5fuMeDDH_6MZgQ5dgP7moY-yTiKR5kdPm-LkuPM-mOtUsylWPd1wpRmvw_AGOZ1UUCa6UD5Hg",
    "scope": "https://www.googleapis.com/auth/calendar.readonly",
    "login_hint": "AJDLj6I2d1RH77cgpe__DdEree1zxHjZJr4Q7yOisoumTZUmo5W2ZmVFHyAomUYzLkrluG-hqt4RnNxrPhArd5y6p8kzO0t8xIfMAe6yhztt6v2E-_Bb4Ec3GLFKikHSXNh5bI-gPrsI",
    "expires_in": 3599,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjkzNDFhYmM0MDkyYjZmYzAzOGU0MDNjOTEwMjJkZDNlNDQ1MzliNTYiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTE3NzI2NDMxNjUxOTQzNjk4NjAwIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkJBSW55TjN2MS1ZejNLQnJUMVo0ckEiLCJuYW1lIjoiQnJpYW4gRGF1Z2hlcnR5IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdnenAyTXNGRGZvbVdMX3VDemRYUWNzeVM3ZGtxTE5ybk90S0QzVXNRPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkJyaWFuIiwiZmFtaWx5X25hbWUiOiJEYXVnaGVydHkiLCJsb2NhbGUiOiJlbiIsImlhdCI6MTYzODk5MTYzOCwiZXhwIjoxNjM4OTk1MjM4LCJqdGkiOiI5YmRkZjE1YWFiNzE2ZDhjYmJmNDYwMmM1YWM3YzViN2VhMDQ5OTA5In0.K3EA-3Adw5HA7O8nJVCsX1HmGWxWzYk3P7ViVBb4H4BoT2-HIgxKlx1mi6jSxIUJGEekjw9MC-nL1B9Asgv1vXTMgoGaNna0UoEHYitySI23E5jaMkExkTSLtxI-ih2tJrA2ggfA9Ekj-JFiMc6MuJnwcfBTlsYWRcZOYVw3QpdTZ_VYfhUu-yERAElZCjaAyEXLtVQegRe-ymScra3r9S92TA33ylMb3WDTlfmDpWL0CDdDzby2asXYpl6GQ7SdSj64s49Yw6mdGELZn5WoJqG7Zr2KwIGXJuSxEo-wGbzxNK-mKAiABcFpYP4KHPEUgYyz3n9Vqn2Tfrgp-g65BQ",
    "session_state": {
      "extraQueryParams": {
        "authuser": "0"
      }
    },
    "first_issued_at": 1638991637982,
    "expires_at": 1638995236982,
    "idpId": "google"
  }

Dane logowania Google Identity Services

Biblioteka Google Identity Services zwraca:

  • token dostępu, gdy jest używany do autoryzacji:

    {
      "access_token": "ya29.A0ARrdaM_LWSO-uckLj7IJVNSfnUityT0Xj-UCCrGxFQdxmLiWuAosnAKMVQ2Z0LLqeZdeJii3TgULp6hR_PJxnInBOl8UoUwWoqsrGQ7-swxgy97E8_hnzfhrOWyQBmH6zs0_sUCzwzhEr_FAVqf92sZZHphr0g",
      "token_type": "Bearer",
      "expires_in": 3599,
      "scope": "https://www.googleapis.com/auth/calendar.readonly"
    }
    
  • lub token tożsamości, gdy jest używany do uwierzytelniania:

    {
      "clientId": "538344653255-758c5h5isc45vgk27d8h8deabovpg6to.apps.googleusercontent.com",
      "credential": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxODkyZWI0OWQ3ZWY5YWRmOGIyZTE0YzA1Y2EwZDAzMjcxNGEyMzciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2MzkxNTcyNjQsImF1ZCI6IjUzODM0NDY1MzI1NS03NThjNWg1aXNjNDV2Z2syN2Q4aDhkZWFib3ZwZzZ0by5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNzcyNjQzMTY1MTk0MzY5ODYwMCIsIm5vbmNlIjoiZm9vYmFyIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkJyaWFuIERhdWdoZXJ0eSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHZ3pwMk1zRkRmb21XTF91Q3pkWFFjc3lTN2RrcUxOcm5PdEtEM1VzUT1zOTYtYyIsImdpdmVuX25hbWUiOiJCcmlhbiIsImZhbWlseV9uYW1lIjoiRGF1Z2hlcnR5IiwiaWF0IjoxNjM5MTU3NTY0LCJleHAiOjE2MzkxNjExNjQsImp0aSI6IjRiOTVkYjAyZjU4NDczMmUxZGJkOTY2NWJiMWYzY2VhYzgyMmI0NjUifQ.Cr-AgMsLFeLurnqyGpw0hSomjOCU4S3cU669Hyi4VsbqnAV11zc_z73o6ahe9Nqc26kPVCNRGSqYrDZPfRyTnV6g1PIgc4Zvl-JBuy6O9HhClAK1HhMwh1FpgeYwXqrng1tifmuotuLQnZAiQJM73Gl-J_6s86Buo_1AIx5YAKCucYDUYYdXBIHLxrbALsA5W6pZCqqkMbqpTWteix-G5Q5T8LNsfqIu_uMBUGceqZWFJALhS9ieaDqoxhIqpx_89QAr1YlGu_UO6R6FYl0wDT-nzjyeF5tonSs3FHN0iNIiR3AMOHZu7KUwZaUdHg4eYkU-sQ01QNY_11keHROCRQ",
      "select_by": "user"
    }
    

Nieprawidłowa odpowiedź tokena

Przykładowa odpowiedź Google podczas próby wysłania żądania do interfejsu API przy użyciu wygasłego, unieważnionego lub nieprawidłowego tokena dostępu:

Nagłówki odpowiedzi HTTP

  www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"

Treść odpowiedzi

  {
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "errors": [
        {
          "message": "Invalid Credentials",
          "domain": "global",
          "reason": "authError",
          "location": "Authorization",
          "locationType": "header"
        }
      ],
      "status": "UNAUTHENTICATED"
    }
  }