Di chuyển sang Dịch vụ nhận dạng của Google

Tổng quan

Để lấy mã truy cập cho mỗi người dùng để gọi API của Google, Google cung cấp nhiều thư viện JavaScript:

Hướng dẫn này cung cấp các chỉ dẫn để di chuyển từ những thư viện này sang thư viện Dịch vụ nhận dạng của Google.

Khi làm theo hướng dẫn này, bạn sẽ:

  • thay thế Thư viện nền tảng đã ngừng hoạt động bằng thư viện Dịch vụ nhận dạng và
  • nếu đang sử dụng Thư viện ứng dụng API, hãy xoá mô-đun gapi.auth2 không dùng nữa, các phương thức và đối tượng của mô-đun này, đồng thời thay thế bằng các thành phần tương đương của Dịch vụ nhận dạng.

Để biết nội dung mô tả về những thay đổi đối với thư viện JavaScript của Dịch vụ nhận dạng, hãy đọc thông tin tổng quancách hoạt động của tính năng uỷ quyền người dùng để xem các thuật ngữ và khái niệm chính.

Nếu bạn đang tìm cách xác thực để người dùng đăng ký và đăng nhập, hãy xem phần Di chuyển từ tính năng Đăng nhập bằng Google.

Xác định quy trình uỷ quyền

Có 2 quy trình uỷ quyền người dùng có thể xảy ra: ngầm ẩn và mã uỷ quyền.

Xem xét ứng dụng web của bạn để xác định loại quy trình uỷ quyền đang được sử dụng.

Các dấu hiệu cho thấy ứng dụng web của bạn đang sử dụng luồng ngầm:

  • Ứng dụng web của bạn hoàn toàn dựa trên trình duyệt, không có nền tảng phụ trợ.
  • Người dùng phải có mặt để gọi API của Google, ứng dụng của bạn chỉ sử dụng mã truy cập và không yêu cầu mã làm mới.
  • Ứng dụng web của bạn tải apis.google.com/js/api.js.
  • Quy trình triển khai của bạn dựa trên OAuth 2.0 cho ứng dụng web phía máy khách.
  • Ứng dụng của bạn sử dụng mô-đun gapi.client hoặc gapi.auth2 có trong Thư viện ứng dụng API của Google cho JavaScript.

Dấu hiệu cho thấy ứng dụng web của bạn đang sử dụng quy trình mã uỷ quyền:

  • Việc triển khai của bạn dựa trên:

  • Ứng dụng của bạn sẽ thực thi cả trong trình duyệt của người dùng và trên nền tảng phụ trợ của bạn.

  • Nền tảng phụ trợ của bạn lưu trữ một điểm cuối mã uỷ quyền.

  • Nền tảng phụ trợ của bạn gọi các API của Google thay cho người dùng mà không yêu cầu họ phải có mặt, còn được gọi là chế độ ngoại tuyến.

  • Mã làm mới do nền tảng phụ trợ của bạn quản lý và lưu trữ.

Trong một số trường hợp, cơ sở mã của bạn có thể hỗ trợ cả hai quy trình.

Chọn một quy trình uỷ quyền

Trước khi bắt đầu di chuyển, bạn cần xác định xem việc tiếp tục sử dụng quy trình hiện tại hay áp dụng một quy trình khác sẽ đáp ứng tốt nhất nhu cầu của bạn.

Hãy xem phần chọn một quy trình uỷ quyền để hiểu rõ những điểm khác biệt và điểm đánh đổi chính giữa hai quy trình này.

Trong hầu hết các trường hợp, bạn nên sử dụng quy trình mã uỷ quyền vì quy trình này mang đến mức độ bảo mật cao nhất cho người dùng. Việc triển khai quy trình này cũng cho phép nền tảng của bạn thêm các chức năng mới khi không có mạng, chẳng hạn như tìm nạp thông tin cập nhật để thông báo cho người dùng về những thay đổi đáng chú ý đối với lịch, ảnh và gói thuê bao của họ.

Chọn một quy trình uỷ quyền bằng cách sử dụng bộ chọn.

Luồng ngầm

Lấy mã thông báo truy cập để sử dụng trong trình duyệt khi người dùng đang hoạt động.

Ví dụ về luồng ngầm cho thấy các ứng dụng web trước và sau khi di chuyển sang Identity Services.

Quy trình sử dụng mã uỷ quyền

Mã uỷ quyền cho mỗi người dùng do Google phát hành sẽ được gửi đến nền tảng phụ trợ của bạn, sau đó mã này sẽ được trao đổi để lấy mã truy cập và mã làm mới.

Ví dụ về quy trình mã uỷ quyền cho thấy các ứng dụng web trước và sau khi di chuyển sang Dịch vụ định danh.

Trong suốt hướng dẫn này, hãy làm theo hướng dẫn được liệt kê bằng chữ in đậm để Thêm, Xoá, Cập nhật hoặc Thay thế chức năng hiện có.

Các thay đổi đối với ứng dụng web trong trình duyệt

Phần này xem xét những thay đổi mà bạn sẽ thực hiện đối với ứng dụng web trong trình duyệt khi di chuyển sang thư viện JavaScript Dịch vụ nhận dạng của Google.

Xác định mã bị ảnh hưởng và kiểm thử

Cookie gỡ lỗi có thể giúp xác định mã bị ảnh hưởng và kiểm thử hành vi sau khi ngừng sử dụng.

Trong các ứng dụng lớn hoặc phức tạp, bạn có thể khó tìm thấy tất cả mã bị ảnh hưởng bởi việc ngừng sử dụng mô-đun gapi.auth2. Để ghi lại việc sử dụng chức năng sắp ngừng hoạt động hiện có vào bảng điều khiển, hãy đặt giá trị của cookie G_AUTH2_MIGRATION thành informational. Nếu muốn, hãy thêm dấu hai chấm, sau đó là một giá trị khoá để cũng ghi vào bộ nhớ phiên. Sau khi đăng nhập và nhận được thông tin đăng nhập, hãy xem xét hoặc gửi nhật ký đã thu thập đến một dịch vụ phụ trợ để phân tích sau. Ví dụ: informational:showauth2use lưu nguồn gốc và URL vào một khoá lưu trữ phiên có tên là showauth2use.

Để xác minh hành vi của ứng dụng khi mô-đun gapi.auth2 không còn được tải, hãy đặt giá trị của cookie G_AUTH2_MIGRATION thành enforced. Điều này cho phép bạn kiểm thử hành vi sau khi ngừng sử dụng trước ngày thực thi.

Các giá trị cookie G_AUTH2_MIGRATION có thể có:

  • enforced Không tải mô-đun gapi.auth2.
  • informational Ghi nhật ký việc sử dụng chức năng không dùng nữa vào bảng điều khiển JS. Cũng ghi vào bộ nhớ phiên khi bạn đặt tên khoá không bắt buộc: informational:key-name.

Để giảm thiểu tác động đến người dùng, trước tiên, bạn nên đặt cookie này cục bộ trong quá trình phát triển và thử nghiệm, trước khi sử dụng trong môi trường sản xuất.

Thư viện và mô-đun

Mô-đun gapi.auth2 quản lý hoạt động xác thực người dùng để đăng nhập và quy trình ngầm định để uỷ quyền, thay thế mô-đun không dùng nữa này, cũng như các đối tượng và phương thức của mô-đun này bằng thư viện Dịch vụ nhận dạng của Google.

Thêm thư viện Dịch vụ định danh vào ứng dụng web của bạn bằng cách đưa thư viện này vào tài liệu:

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

Xoá mọi trường hợp tải mô-đun auth2 bằng gapi.load('auth2', function).

Thư viện Dịch vụ nhận dạng của Google thay thế việc sử dụng mô-đun gapi.auth2. Bạn có thể tiếp tục sử dụng mô-đun gapi.client một cách an toàn trong Thư viện ứng dụng API của Google cho JavaScript và tận dụng khả năng tự động tạo các phương thức JS có thể gọi từ tài liệu khám phá, gộp nhiều lệnh gọi API và chức năng quản lý CORS.

Bánh quy

Bạn không cần sử dụng cookie để uỷ quyền cho người dùng.

Hãy xem phần Di chuyển từ tính năng Đăng nhập bằng Google để biết thông tin chi tiết về cách xác thực người dùng sử dụng cookie và phần Cách Google sử dụng cookie để biết cách các sản phẩm và dịch vụ khác của Google sử dụng cookie.

Thông tin xác thực

Dịch vụ nhận dạng của Google tách hoạt động xác thực và uỷ quyền người dùng thành hai thao tác riêng biệt, đồng thời thông tin đăng nhập của người dùng cũng tách biệt: mã thông báo nhận dạng dùng để xác định người dùng được trả về riêng biệt với mã thông báo truy cập dùng cho hoạt động uỷ quyền.

Để xem những thay đổi này, hãy xem ví dụ về thông tin đăng nhập.

Luồng ngầm

Tách quy trình xác thực và uỷ quyền người dùng bằng cách xoá quy trình xử lý hồ sơ người dùng khỏi các luồng uỷ quyền.

Xoá những tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google sau đây:

Phương thức

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

Quy trình sử dụng mã uỷ quyền

Identity Services tách thông tin đăng nhập trong trình duyệt thành mã thông báo nhận dạng và mã thông báo truy cập. Thay đổi này không áp dụng cho thông tin đăng nhập thu được thông qua các lệnh gọi trực tiếp đến các điểm cuối OAuth 2.0 của Google từ nền tảng phụ trợ của bạn hoặc thông qua các thư viện chạy trên một máy chủ bảo mật trên nền tảng của bạn, chẳng hạn như Ứng dụng Google API Node.js.

Trạng thái phiên

Trước đây, tính năng Đăng nhập bằng Google giúp bạn quản lý trạng thái đăng nhập của người dùng bằng cách sử dụng:

Bạn chịu trách nhiệm quản lý trạng thái đăng nhập và phiên người dùng cho ứng dụng web của mình.

Xoá những tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google sau đây:

Đối tượng:

  • gapi.auth2.SignInOptions

Phương pháp:

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

Cấu hình ứng dụng

Cập nhật ứng dụng web để khởi tạo một ứng dụng khách mã thông báo cho luồng mã uỷ quyền hoặc ngầm ẩn.

Xoá những tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google sau đây:

Đối tượng:

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

Phương pháp:

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

Luồng ngầm

Thêm một đối tượng TokenClientConfig và lệnh gọi initTokenClient() để định cấu hình ứng dụng web của bạn, theo ví dụ trong phần khởi tạo một ứng dụng khách mã thông báo.

Thay thế các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google bằng Dịch vụ nhận dạng của Google:

Đối tượng:

  • gapi.auth2.AuthorizeConfig với TokenClientConfig

Phương pháp:

  • gapi.auth2.init() với google.accounts.oauth2.initTokenClient()

Các thông số:

  • gapi.auth2.AuthorizeConfig.login_hint với TokenClientConfig.login_hint.
  • gapi.auth2.GoogleUser.getHostedDomain() với TokenClientConfig.hd.

Quy trình sử dụng mã uỷ quyền

Thêm một đối tượng CodeClientConfig và lệnh gọi initCodeClient() để định cấu hình ứng dụng web của bạn, theo ví dụ trong phần khởi chạy một Code Client.

Khi chuyển từ quy trình ngầm định sang quy trình sử dụng mã uỷ quyền:

Xoá các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google

Đối tượng:

  • gapi.auth2.AuthorizeConfig

Phương pháp:

  • gapi.auth2.init()

Các thông số:

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

Yêu cầu mã thông báo

Một thao tác của người dùng (chẳng hạn như nhấp vào nút) sẽ tạo ra một yêu cầu dẫn đến việc mã truy cập được trả về trực tiếp cho trình duyệt của người dùng bằng luồng ngầm ẩn hoặc cho nền tảng phụ trợ của bạn sau khi trao đổi mã uỷ quyền cho mỗi người dùng để lấy mã truy cập và mã làm mới.

Luồng ngầm

Bạn có thể lấy và sử dụng mã truy cập trong trình duyệt khi người dùng đã đăng nhập và có một phiên hoạt động với Google. Đối với chế độ ngầm ẩn, người dùng cần thực hiện một cử chỉ để yêu cầu mã truy cập, ngay cả khi trước đó đã có một yêu cầu.

Thay thế các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google bằng Dịch vụ danh tính của Google:

Phương pháp:

  • gapi.auth2.authorize() với TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() với TokenClient.requestAccessToken()

Thêm một đường liên kết hoặc nút để gọi requestAccessToken() nhằm bắt đầu quy trình UX bật lên để yêu cầu mã truy cập hoặc để lấy mã thông báo mới khi mã thông báo hiện có hết hạn.

Cập nhật cơ sở mã của bạn thành:

  • Kích hoạt quy trình mã thông báo OAuth 2.0 bằng requestAccessToken().
  • Hỗ trợ uỷ quyền gia tăng bằng cách sử dụng requestAccessTokenOverridableTokenClientConfig để tách một yêu cầu cho nhiều phạm vi thành nhiều yêu cầu nhỏ hơn.
  • Yêu cầu mã thông báo mới khi mã thông báo hiện có hết hạn hoặc bị thu hồi.

Việc sử dụng nhiều phạm vi có thể yêu cầu các thay đổi về cấu trúc đối với cơ sở mã của bạn để chỉ yêu cầu quyền truy cập vào các phạm vi khi cần thay vì tất cả cùng một lúc. Điều này được gọi là uỷ quyền gia tăng. Mỗi yêu cầu nên chứa ít phạm vi nhất có thể và tốt nhất là một phạm vi duy nhất. Hãy xem cách xử lý sự đồng ý của người dùng để biết thêm thông tin về cách cập nhật ứng dụng cho hoạt động uỷ quyền gia tăng.

Khi mã truy cập hết hạn, mô-đun gapi.auth2 sẽ tự động lấy một mã truy cập mới, hợp lệ cho ứng dụng web của bạn. Để cải thiện tính bảo mật cho người dùng, thư viện Dịch vụ nhận dạng của Google không hỗ trợ quy trình làm mới mã thông báo tự động này. Bạn phải cập nhật ứng dụng web để phát hiện mã thông báo truy cập đã hết hạn và yêu cầu mã thông báo mới. Hãy xem phần Xử lý mã thông báo để biết thêm thông tin.

Quy trình sử dụng mã uỷ quyền

Thêm một đường liên kết hoặc nút để gọi requestCode() nhằm yêu cầu mã uỷ quyền từ Google. Để xem ví dụ, hãy xem phần Kích hoạt quy trình mã OAuth 2.0.

Hãy xem phần Xử lý mã thông báo để biết thêm thông tin về cách phản hồi mã truy cập đã hết hạn hoặc bị thu hồi.

Xử lý mã thông báo

Thêm tính năng xử lý lỗi để phát hiện các lệnh gọi API Google không thành công khi sử dụng mã truy cập đã hết hạn hoặc bị thu hồi, đồng thời yêu cầu một mã truy cập mới, hợp lệ.

API của Google trả về mã trạng thái HTTP là 401 Unauthorized và thông báo lỗi invalid_token khi bạn dùng mã truy cập đã hết hạn hoặc bị thu hồi. Để xem ví dụ, hãy xem phần Phản hồi mã thông báo không hợp lệ.

Mã thông báo đã hết hạn

Mã truy cập có thời hạn ngắn và thường chỉ có hiệu lực trong vài phút.

Thu hồi mã thông báo

Bất cứ lúc nào, chủ sở hữu Tài khoản Google đều có thể thu hồi sự đồng ý đã cấp trước đó. Việc này sẽ làm mất hiệu lực mã truy cập và mã làm mới hiện có. Bạn có thể thu hồi từ nền tảng của mình bằng cách sử dụng revoke() hoặc thông qua Tài khoản Google.

Thay thế các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google bằng Dịch vụ danh tính của Google:

Phương pháp:

  • getAuthInstance().disconnect() với google.accounts.oauth2.revoke()
  • GoogleUser.disconnect() với google.accounts.oauth2.revoke()

Gọi revoke khi người dùng xoá tài khoản của họ trên nền tảng của bạn hoặc muốn huỷ đồng ý chia sẻ dữ liệu với ứng dụng của bạn.

Google sẽ hiển thị hộp thoại đồng ý cho người dùng khi ứng dụng web hoặc nền tảng phụ trợ của bạn yêu cầu mã truy cập. Xem ví dụ về hộp thoại đồng ý do Google hiển thị cho người dùng.

Trước khi cấp mã truy cập cho ứng dụng của bạn, bạn cần có một phiên hoạt động hiện tại và đang hoạt động trên Google để nhắc người dùng đồng ý và ghi lại kết quả. Người dùng có thể phải đăng nhập vào Tài khoản Google nếu chưa thiết lập phiên hiện có.

Đăng nhập người dùng

Người dùng có thể đăng nhập vào Tài khoản Google trong một thẻ trình duyệt riêng biệt hoặc một cách tự nhiên thông qua trình duyệt hoặc hệ điều hành. Bạn nên thêm tính năng Đăng nhập bằng Google vào trang web của mình để thiết lập một phiên hoạt động giữa Tài khoản Google và trình duyệt khi người dùng mở ứng dụng của bạn lần đầu tiên. Việc này mang lại những lợi ích sau:

  • Giảm thiểu số lần người dùng phải đăng nhập, yêu cầu mã truy cập sẽ bắt đầu quy trình đăng nhập bằng Tài khoản Google nếu chưa có phiên hoạt động.
  • Sử dụng trực tiếp trường thông tin đăng nhập email của JWT ID Token làm giá trị của tham số login_hint trong các đối tượng CodeClientConfig hoặc TokenClientConfig. Điều này đặc biệt hữu ích nếu nền tảng của bạn không duy trì hệ thống quản lý tài khoản người dùng.
  • Tra cứu và liên kết Tài khoản Google với tài khoản người dùng cục bộ hiện có trên nền tảng của bạn, giúp giảm thiểu tài khoản trùng lặp trên nền tảng của bạn.
  • Khi một tài khoản mới, cục bộ được tạo, các hộp thoại và quy trình đăng ký của bạn có thể tách biệt rõ ràng với các hộp thoại và quy trình xác thực người dùng, giảm số bước bắt buộc và cải thiện tỷ lệ bỏ qua.

Sau khi đăng nhập và trước khi mã truy cập được phát hành, người dùng phải đồng ý cho ứng dụng của bạn đối với các phạm vi được yêu cầu.

Sau khi người dùng đồng ý, mã truy cập sẽ được trả về cùng với danh sách các phạm vi mà người dùng đã phê duyệt hoặc từ chối.

Quyền chi tiết cho phép người dùng phê duyệt hoặc từ chối từng phạm vi. Khi yêu cầu quyền truy cập vào nhiều phạm vi, mỗi phạm vi sẽ được cấp hoặc bị từ chối độc lập với các phạm vi khác. Dựa trên lựa chọn của người dùng, ứng dụng của bạn sẽ chọn lọc để bật các tính năng và chức năng phụ thuộc vào một phạm vi riêng lẻ.

Luồng ngầm

Thay thế các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google bằng Dịch vụ nhận dạng của Google:

Đối tượng:

  • gapi.auth2.AuthorizeResponse với TokenClient.TokenResponse
  • gapi.auth2.AuthResponse với TokenClient.TokenResponse

Phương pháp:

  • GoogleUser.hasGrantedScopes() với google.accounts.oauth2.hasGrantedAllScopes()
  • GoogleUser.getGrantedScopes() với google.accounts.oauth2.hasGrantedAllScopes()

Xoá các tham chiếu đến ứng dụng JavaScript Đăng nhập bằng Google:

Phương pháp:

  • GoogleUser.getAuthResponse()

Cập nhật ứng dụng web của bạn bằng hasGrantedAllScopes()hasGrantedAnyScope() bằng cách làm theo ví dụ về quyền chi tiết này.

Quy trình sử dụng mã uỷ quyền

Cập nhật hoặc Thêm một điểm cuối mã uỷ quyền vào nền tảng phụ trợ của bạn bằng cách làm theo hướng dẫn trong phần xử lý mã uỷ quyền.

Cập nhật nền tảng của bạn để làm theo các bước được mô tả trong hướng dẫn Sử dụng mô hình mã để xác thực yêu cầu và lấy mã truy cập cũng như mã làm mới.

Cập nhật nền tảng của bạn để chọn lọc bật hoặc tắt các tính năng và chức năng dựa trên từng phạm vi mà người dùng đã phê duyệt bằng cách làm theo hướng dẫn về uỷ quyền gia tăngkiểm tra phạm vi truy cập mà người dùng đã cấp.

Ví dụ về luồng ngầm ẩn

Cách cũ

Thư viện ứng dụng GAPI

Ví dụ về Thư viện ứng dụng API của Google cho JavaScript đang chạy trong trình duyệt bằng cách sử dụng hộp thoại bật lên để lấy sự đồng ý của người dùng.

gapi.auth2 được gapi.client.init() tự động tải và sử dụng, nên sẽ bị ẩn.

<!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>

Thư viện ứng dụng JS

OAuth 2.0 cho ứng dụng web phía máy khách chạy trong trình duyệt bằng cách sử dụng hộp thoại bật lên để lấy sự đồng ý của người dùng.

Mô-đun gapi.auth2 được tải theo cách thủ công.

<!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>

Điểm cuối OAuth 2.0

OAuth 2.0 cho ứng dụng web phía máy khách chạy trong trình duyệt bằng cách chuyển hướng đến Google để lấy sự đồng ý của người dùng.

Ví dụ này cho thấy các lệnh gọi trực tiếp đến các điểm cuối OAuth 2.0 của Google từ trình duyệt của người dùng và không sử dụng mô-đun gapi.auth2 hoặc thư viện 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>

Cách thức mới

Chỉ GIS

Ví dụ này chỉ minh hoạ thư viện JavaScript Dịch vụ nhận dạng của Google bằng cách sử dụng mô hình mã thông báo và hộp thoại bật lên để lấy sự đồng ý của người dùng. Mã này được cung cấp để minh hoạ số lượng tối thiểu các bước cần thiết để định cấu hình một ứng dụng, yêu cầu và lấy mã truy cập, đồng thời gọi một API của 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

Ví dụ này cho thấy cách thêm thư viện Dịch vụ nhận dạng của Google bằng mô hình mã thông báo, xoá mô-đun gapi.auth2 và gọi một API bằng Thư viện ứng dụng API của Google cho JavaScript.

Các promise, async và await được dùng để thực thi thứ tự tải thư viện, cũng như để bắt và thử lại các lỗi uỷ quyền. Bạn chỉ có thể thực hiện lệnh gọi API sau khi có mã thông báo truy cập hợp lệ.

Người dùng dự kiến sẽ nhấn nút "Hiện lịch" khi mã truy cập bị thiếu trong lần đầu tiên trang được tải hoặc sau khi mã truy cập hết hạn.

<!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>

Lệnh gọi lại GAPI

Ví dụ này cho thấy cách thêm thư viện Dịch vụ nhận dạng của Google bằng mô hình mã thông báo, xoá mô-đun gapi.auth2 và gọi một API bằng Thư viện ứng dụng API của Google cho JavaScript.

Các biến được dùng để thực thi thứ tự tải thư viện. Các lệnh gọi GAPI được thực hiện từ trong lệnh gọi lại sau khi mã truy cập hợp lệ được trả về.

Người dùng dự kiến sẽ nhấn nút Hiện lịch khi trang được tải lần đầu và nhấn lại khi họ muốn làm mới thông tin Lịch.

<!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>

Ví dụ về quy trình sử dụng mã uỷ quyền

UX của cửa sổ bật lên trong thư viện Dịch vụ nhận dạng của Google có thể sử dụng một lệnh chuyển hướng URL để trả về mã uỷ quyền trực tiếp cho điểm cuối mã thông báo phụ trợ của bạn hoặc một trình xử lý lệnh gọi lại JavaScript chạy trong trình duyệt của người dùng, trình xử lý này sẽ chuyển tiếp phản hồi đến nền tảng của bạn. Trong cả hai trường hợp, nền tảng phụ trợ của bạn sẽ hoàn tất quy trình OAuth 2.0 để lấy mã làm mới và mã truy cập hợp lệ.

Cách cũ

Ứng dụng web phía máy chủ

Tính năng Đăng nhập bằng Google cho các ứng dụng phía máy chủ đang chạy trên nền tảng phụ trợ bằng cách sử dụng lệnh chuyển hướng đến Google để người dùng đồng ý.

<!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 sử dụng lệnh chuyển hướng

Sử dụng OAuth 2.0 cho ứng dụng máy chủ web để gửi mã uỷ quyền từ trình duyệt của người dùng đến nền tảng phụ trợ của bạn. Sự đồng ý của người dùng được xử lý bằng cách chuyển hướng trình duyệt của người dùng đến 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();
}

Cách thức mới

Trải nghiệm người dùng của cửa sổ bật lên GIS

Ví dụ này chỉ cho thấy thư viện JavaScript Dịch vụ nhận dạng của Google sử dụng mô hình mã uỷ quyền, một hộp thoại bật lên để người dùng đồng ý và trình xử lý lệnh gọi lại để nhận mã uỷ quyền từ Google. Mã này được cung cấp để minh hoạ số lượng tối thiểu các bước cần thiết để định cấu hình một ứng dụng khách, thu thập sự đồng ý và gửi mã uỷ quyền đến nền tảng phụ trợ của bạn.

<!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>

Trải nghiệm người dùng chuyển hướng GIS

Mô hình mã uỷ quyền hỗ trợ các chế độ UX bật lên và chuyển hướng để gửi mã uỷ quyền cho mỗi người dùng đến điểm cuối do nền tảng của bạn lưu trữ. Chế độ chuyển hướng UX được minh hoạ ở đây:

<!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>

Thư viện JavaScript

Dịch vụ nhận dạng của Google là một thư viện JavaScript duy nhất được dùng để xác thực và uỷ quyền cho người dùng, đồng thời hợp nhất và thay thế các tính năng và chức năng có trong nhiều thư viện và mô-đun khác nhau:

Những việc cần làm khi di chuyển sang Identity Services:

Thư viện JS hiện có Thư viện JS mới Ghi chú
apis.google.com/js/api.js accounts.google.com/gsi/client Thêm thư viện mới và làm theo quy trình ngầm.
apis.google.com/js/client.js accounts.google.com/gsi/client Thêm thư viện mới và quy trình mã uỷ quyền.

Thông tin tham khảo nhanh về thư viện

So sánh đối tượng và phương thức giữa thư viện JavaScript sử dụng tính năng đăng nhập bằng Google và thư viện Mới Dịch vụ nhận dạng của GoogleGhi chú kèm theo thông tin bổ sung và hành động cần thực hiện trong quá trình di chuyển.

Mới Ghi chú
Đối tượng GoogleAuth và các phương thức liên kết:
GoogleAuth.attachClickHandler() Xóa
GoogleAuth.currentUser.get() Xóa
GoogleAuth.currentUser.listen() Xóa
GoogleAuth.disconnect() google.accounts.oauth2.revoke Thay thế cái cũ bằng cái mới. Bạn cũng có thể thu hồi quyền truy cập trên trang https://myaccount.google.com/permissions
GoogleAuth.grantOfflineAccess() Xoá, hãy làm theo quy trình sử dụng mã uỷ quyền.
GoogleAuth.isSignedIn.get() Xóa
GoogleAuth.isSignedIn.listen() Xóa
GoogleAuth.signIn() Xóa
GoogleAuth.signOut() Xóa
GoogleAuth.then() Xóa
Đối tượng GoogleUser và các phương thức liên kết:
GoogleUser.disconnect() google.accounts.id.revoke Thay thế cái cũ bằng cái mới. Bạn cũng có thể thu hồi quyền truy cập trên trang https://myaccount.google.com/permissions
GoogleUser.getAuthResponse() requestCode() or requestAccessToken() Thay thế cái cũ bằng cái mới
GoogleUser.getBasicProfile() Xóa. Thay vào đó, hãy sử dụng Mã thông báo nhận dạng, xem phần Di chuyển từ tính năng Đăng nhập bằng Google.
GoogleUser.getGrantedScopes() hasGrantedAnyScope() Thay thế cái cũ bằng cái mới
GoogleUser.getHostedDomain() Xóa
GoogleUser.getId() Xóa
GoogleUser.grantOfflineAccess() Xoá, hãy làm theo quy trình sử dụng mã uỷ quyền.
GoogleUser.grant() Xóa
GoogleUser.hasGrantedScopes() hasGrantedAnyScope() Thay thế cái cũ bằng cái mới
GoogleUser.isSignedIn() Xóa
GoogleUser.reloadAuthResponse() requestAccessToken() Xoá mã truy cập cũ, gọi mã truy cập mới để thay thế mã truy cập đã hết hạn hoặc bị thu hồi.
Đối tượng gapi.auth2 và các phương thức liên kết:
đối tượng gapi.auth2.AuthorizeConfig TokenClientConfig hoặc CodeClientConfig Thay thế cái cũ bằng cái mới
đối tượng gapi.auth2.AuthorizeResponse Xóa
đối tượng gapi.auth2.AuthResponse Xóa
gapi.auth2.authorize() requestCode() or requestAccessToken() Thay thế cái cũ bằng cái mới
gapi.auth2.ClientConfig() TokenClientConfig hoặc CodeClientConfig Thay thế cái cũ bằng cái mới
gapi.auth2.getAuthInstance() Xóa
gapi.auth2.init() initTokenClient() or initCodeClient() Thay thế cái cũ bằng cái mới
Đối tượng gapi.auth2.OfflineAccessOptions Xóa
Đối tượng gapi.auth2.SignInOptions Xóa
Đối tượng gapi.signin2 và các phương thức liên kết:
gapi.signin2.render() Xóa. Việc tải HTML DOM của phần tử g_id_signin hoặc lệnh gọi JS đến google.accounts.id.renderButton sẽ kích hoạt quá trình đăng nhập của người dùng vào Tài khoản Google.

Thông tin đăng nhập mẫu

Thông tin xác thực hiện có

Thư viện nền tảng Đăng nhập bằng Google, Thư viện ứng dụng Google API cho JavaScript hoặc các lệnh gọi trực tiếp đến các điểm cuối OAuth 2.0 của Google sẽ trả về cả mã truy cập OAuth 2.0 và Mã thông báo OpenID Connect trong một phản hồi duy nhất.

Ví dụ về phản hồi chứa cả access_tokenid_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"
  }

Thông tin đăng nhập của Dịch vụ nhận dạng của Google

Thư viện Dịch vụ nhận dạng của Google trả về:

  • mã truy cập khi được dùng để uỷ quyền:

    {
      "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"
    }
    
  • hoặc mã nhận dạng khi dùng để xác thực:

    {
      "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"
    }
    

Phản hồi mã thông báo không hợp lệ

Ví dụ về phản hồi của Google khi cố gắng thực hiện một yêu cầu API bằng mã truy cập đã hết hạn, bị thu hồi hoặc không hợp lệ:

Tiêu đề phản hồi HTTP

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

Nội dung phản hồi

  {
    "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"
    }
  }