Sử dụng OAuth 2.0 cho ứng dụng từ máy chủ đến máy chủ

Các mục trong Để biết thêm thông tin, hãy xem phần Tổng quan về xác thực trong tài liệu về Google Cloud Platform.

Hệ thống Google OAuth 2.0 hỗ trợ các hoạt động tương tác giữa các máy chủ, chẳng hạn như giữa một ứng dụng web và một dịch vụ của Google. Trong trường hợp này, bạn cần có một tài khoản dịch vụ. Tài khoản này là của một ứng dụng thay vì của một người dùng cuối. Ứng dụng của bạn gọi API Google thay mặt cho tài khoản dịch vụ, vì vậy, người dùng không tham gia trực tiếp. Tình huống này đôi khi được gọi là "hai chân OAuth;" hoặc "2LO." (Thuật ngữ liên quan "Ba chân OAuth" đề cập đến những tình huống mà trong đó ứng dụng của bạn thay mặt cho API Google gọi cho người dùng cuối và trong đó đôi khi cần phải có sự đồng ý của người dùng.)

Thông thường, một ứng dụng sử dụng tài khoản dịch vụ khi ứng dụng đó sử dụng các API của Google để làm việc với dữ liệu của chính mình thay vì dữ liệu của người dùng. Ví dụ: một ứng dụng sử dụng kho lưu trữ dữ liệu Google Cloud để lưu trữ dữ liệu sẽ dùng một tài khoản dịch vụ để xác thực các lệnh gọi đến API Google Cloud Datastore.

Quản trị viên miền Google Workspace cũng có thể cấp cho tài khoản dịch vụ quyền trên toàn miền quyền truy cập dữ liệu người dùng thay mặt người dùng trong miền.

Tài liệu này mô tả cách một ứng dụng có thể hoàn tất quy trình OAuth 2.0 từ máy chủ đến máy chủ bằng cách sử dụng thư viện ứng dụng API của Google (nên dùng) hoặc HTTP.

Tổng quan

Để hỗ trợ việc tương tác từ máy chủ đến máy chủ, trước tiên, hãy tạo một tài khoản dịch vụ cho dự án của bạn trong . Nếu bạn muốn truy cập vào dữ liệu người dùng cho người dùng trong tài khoản Google Workspace, hãy ủy quyền truy cập vào toàn bộ miền cho tài khoản dịch vụ đó.

Sau đó, ứng dụng của bạn chuẩn bị thực hiện các lệnh gọi API được ủy quyền bằng cách sử dụng thông tin đăng nhập của tài khoản dịch vụ để yêu cầu mã truy cập từ máy chủ xác thực OAuth 2.0.

Cuối cùng, ứng dụng của bạn có thể sử dụng mã truy cập để gọi API của Google.

Tạo một tài khoản dịch vụ

Thông tin đăng nhập của tài khoản dịch vụ bao gồm một địa chỉ email được tạo riêng và có ít nhất một cặp khóa công khai/riêng tư. Nếu bạn bật tính năng ủy quyền trên toàn miền, thì mã ứng dụng khách cũng sẽ nằm trong thông tin đăng nhập của tài khoản dịch vụ.

Nếu ứng dụng của bạn chạy trên Google App Engine, thì một tài khoản dịch vụ sẽ được thiết lập tự động khi bạn tạo dự án.

Nếu ứng dụng của bạn chạy trên Google Compute Engine, thì tài khoản dịch vụ cũng sẽ được thiết lập tự động khi bạn tạo dự án, nhưng bạn phải chỉ định các phạm vi mà ứng dụng của bạn cần quyền truy cập khi tạo phiên bản Google Compute Engine. Để biết thêm thông tin, hãy xem bài viết Chuẩn bị cho một phiên bản để sử dụng tài khoản dịch vụ.

Nếu ứng dụng của bạn không chạy trên Google App Engine hoặc Google Compute Engine, bạn phải lấy được thông tin xác thực trong . Để tạo thông tin đăng nhập của tài khoản dịch vụ hoặc xem thông tin đăng nhập công khai mà bạn đã tạo, hãy làm như sau:

Đầu tiên, hãy tạo một tài khoản dịch vụ:

  1. Mở Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. Nhấn vào Tạo tài khoản dịch vụ.
  4. Theo chi tiết tài khoản dịch vụ, gõ tên, ID, và mô tả cho tài khoản dịch vụ, sau đó nhấp vào Tạo và tiếp tục.
  5. Tùy chọn: Theo Grant dịch vụ này truy cập tài khoản cho dự án, chọn vai trò IAM cấp cho tài khoản dịch vụ.
  6. Nhấp vào Tiếp tục.
  7. Tùy chọn: Theo Grant người dùng truy cập vào tài khoản của dịch vụ này, thêm người dùng hoặc nhóm được phép sử dụng và quản lý tài khoản dịch vụ.
  8. Nhấn Done.
  9. Nhấn Tạo chìa khóa, sau đó nhấp vào Tạo.

Tiếp theo, tạo khóa tài khoản dịch vụ:

  1. Nhấp vào địa chỉ email cho tài khoản dịch vụ bạn đã tạo.
  2. Nhấp vào tab Keys.
  3. Trong các Thêm chủ chốt danh sách thả xuống, chọn Tạo khóa mới.
  4. Nhấp vào Tạo.

Cặp khóa công khai / riêng tư mới của bạn được tạo và tải xuống máy của bạn; nó đóng vai trò là bản sao duy nhất của khóa cá nhân. Bạn có trách nhiệm lưu trữ nó một cách an toàn. Nếu bạn làm mất cặp khóa này, bạn sẽ cần tạo một cặp khóa mới.

Bạn có thể quay lại API Console bất kỳ lúc nào để xem địa chỉ email, vân tay số công khai và các thông tin khác hoặc tạo thêm cặp khóa công khai/riêng tư. Để biết thêm thông tin chi tiết về thông tin đăng nhập tài khoản dịch vụ trong API Console, hãy xem Tài khoản dịch vụ trong API Console tệp trợ giúp.

Hãy lưu ý địa chỉ email của tài khoản dịch vụ và lưu trữ tệp khóa riêng tư của tài khoản dịch vụ tại một vị trí mà ứng dụng của bạn có thể truy cập. Ứng dụng của bạn cần có quyền này để thực hiện các lệnh gọi API được ủy quyền.

Ủy quyền trên toàn miền cho tài khoản dịch vụ

Nếu bạn có tài khoản Google Workspace, quản trị viên của tổ chức có thể thay mặt người dùng trong miền Google Workspace cấp cho một ứng dụng quyền truy cập vào dữ liệu người dùng. Ví dụ: một ứng dụng dùng API Lịch Google để thêm các sự kiện vào lịch của tất cả người dùng trong miền Google Workspace sẽ thay mặt người dùng sử dụng một tài khoản dịch vụ để truy cập vào API Lịch Google. Việc ủy quyền cho một tài khoản dịch vụ truy cập dữ liệu thay mặt cho người dùng trong một miền đôi khi được gọi là "ủy quyền trên toàn miền" vào một tài khoản dịch vụ.

Để ủy quyền quản lý toàn bộ miền cho một tài khoản dịch vụ, quản trị viên cấp cao của miền Google Workspace phải hoàn thành các bước sau:

  1. Từ Bảng điều khiển dành cho quản trị viên của miền Google Workspace, hãy chuyển đến Trình đơn chính > Bảo mật > Truy cập và kiểm soát dữ liệu > Kiểm soát API.
  2. Trong ngăn Ủy quyền trên toàn miền, hãy chọn Quản lý việc ủy quyền trên toàn miền.
  3. Nhấp vào Thêm mới.
  4. Trong trường Mã ứng dụng, hãy nhập Mã ứng dụng của tài khoản dịch vụ. Bạn có thể tìm thấy mã khách hàng của tài khoản dịch vụ trong Service accounts page.
  5. Trong trường Phạm vi OAuth (phân tách bằng dấu phẩy), hãy nhập danh sách các phạm vi mà ứng dụng của bạn sẽ được cấp quyền truy cập. Ví dụ: nếu ứng dụng của bạn cần quyền truy cập đầy đủ vào toàn bộ miền đối với API Google Drive và API Lịch Google, hãy nhập: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
  6. Nhấp vào Uỷ quyền.

Ứng dụng của bạn hiện có quyền thực hiện lệnh gọi API với tư cách là người dùng trong miền của bạn (đến "impersonate" users). Khi chuẩn bị thực hiện các lệnh gọi API được ủy quyền, bạn chỉ định người dùng nhập vai.

Đang chuẩn bị thực hiện lệnh gọi API được ủy quyền

Java

Sau khi bạn lấy địa chỉ email máy khách và khoá riêng tư từ API Console, hãy sử dụng Thư viện ứng dụng Java cho API của Google để tạo đối tượng GoogleCredential từ thông tin đăng nhập của tài khoản dịch vụ và những phạm vi mà ứng dụng của bạn cần truy cập. Ví dụ:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

Nếu đang phát triển một ứng dụng trên Google Cloud Platform, thì bạn có thể sử dụng thông tin xác thực mặc định của ứng dụng để có thể đơn giản hóa quá trình này.

Ủy quyền trên toàn miền

Nếu bạn được ủy quyền truy cập vào toàn bộ tài khoản dịch vụ và bạn muốn mạo danh tài khoản người dùng, hãy chỉ định địa chỉ email của tài khoản người dùng bằng phương thức createDelegated của đối tượng GoogleCredential. Ví dụ:

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("user@example.com");

Dùng đối tượng GoogleCredential để gọi các API của Google trong ứng dụng của bạn.

Python

Sau khi bạn lấy địa chỉ email máy khách và khóa riêng tư từ API Console, hãy sử dụng Thư viện ứng dụng API của Google cho Python để hoàn thành các bước sau:

  1. Tạo một đối tượng Credentials từ thông tin đăng nhập của tài khoản dịch vụ và các phạm vi mà ứng dụng của bạn cần truy cập. Ví dụ:
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/service.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

    Nếu đang phát triển một ứng dụng trên Google Cloud Platform, thì bạn có thể sử dụng thông tin xác thực mặc định của ứng dụng để có thể đơn giản hóa quá trình này.

  2. Ủy quyền trên toàn miền

    Nếu bạn được ủy quyền truy cập trên toàn miền cho tài khoản dịch vụ và bạn muốn mạo danh tài khoản người dùng, hãy sử dụng phương thức with_subject của đối tượng ServiceAccountCredentials hiện có. Ví dụ:

    delegated_credentials = credentials.with_subject('user@example.org')

Dùng đối tượng Thông tin xác thực để gọi các API của Google trong ứng dụng của bạn.

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

Sau khi bạn có mã ứng dụng khách và khóa riêng tư từ API Console, đơn đăng ký của bạn cần phải hoàn thành các bước sau:

  1. Tạo Mã thông báo web JSON (JWT, phát âm và "jot") bao gồm tiêu đề, bộ thông báo xác nhận quyền sở hữu và chữ ký.
  2. Yêu cầu mã truy cập từ Máy chủ ủy quyền Google OAuth 2.0.
  3. Xử lý phản hồi JSON mà Máy chủ ủy quyền trả về.

Các phần sau mô tả cách hoàn tất các bước này.

Nếu phản hồi bao gồm mã truy cập, bạn có thể sử dụng mã truy cập để gọi API Google. (Nếu phản hồi không bao gồm mã truy cập, có thể yêu cầu JWT và mã thông báo của bạn đã không được định dạng đúng cách hoặc tài khoản dịch vụ có thể không có quyền truy cập vào phạm vi yêu cầu.)

Khi mã truy cập hết hạn, ứng dụng của bạn sẽ tạo một WWT khác, ký mã đó và yêu cầu một mã truy cập khác.

Ứng dụng máy chủ của bạn sử dụng JWT để yêu cầu mã thông báo từ Máy chủ ủy quyền của Google, sau đó sử dụng mã thông báo này để gọi một điểm cuối API của Google. Không
                  người dùng cuối nào tham gia.

Phần còn lại của phần này mô tả thông tin cụ thể về việc tạo JWT, ký JWT, tạo yêu cầu mã thông báo truy cập và xử lý phản hồi.

Tạo JWT

JWT bao gồm 3 phần: tiêu đề, nhóm thông báo xác nhận quyền sở hữu và chữ ký. Tiêu đề và bộ thông báo xác nhận quyền sở hữu là các đối tượng JSON. Các đối tượng JSON này được tuần tự hóa thành các byte UTF-8, sau đó được mã hóa bằng phương thức mã hóa Base64url. Phương thức mã hóa này cung cấp khả năng phục hồi cho các thay đổi mã hóa do các hoạt động mã hóa lặp lại. Tiêu đề, bộ thông báo xác nhận quyền sở hữu và chữ ký được nối với nhau bằng dấu chấm (.).

JWT bao gồm:

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

Chuỗi cơ sở cho chữ ký như sau:

{Base64url encoded header}.{Base64url encoded claim set}
Hình thành tiêu đề JWT

Tiêu đề này có 2 trường cho biết thuật toán ký và định dạng của khẳng định. Cả hai trường đều là bắt buộc và mỗi trường chỉ có một giá trị. Khi chúng tôi triển khai các thuật toán và định dạng khác, tiêu đề này sẽ thay đổi tương ứng.

Tài khoản dịch vụ dựa vào thuật toán SHA-256 của RSA và định dạng mã thông báo JWT. Do đó, biểu diễn JSON của tiêu đề sẽ như sau:

{"alg":"RS256","typ":"JWT"}

Cách trình bày Base64url như sau:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
Tạo đơn khiếu nại JWT

Tập hợp thông báo xác nhận quyền sở hữu JWT chứa thông tin về JWT, bao gồm cả những quyền được yêu cầu (phạm vi), mục tiêu của mã thông báo, nhà phát hành, thời gian phát hành mã và thời gian tồn tại của mã thông báo. Hầu hết các trường đều là bắt buộc. Giống như tiêu đề JWT, tập hợp thông báo xác nhận quyền sở hữu JWT là một đối tượng JSON và được dùng để tính chữ ký.

Thông báo xác nhận quyền sở hữu bắt buộc

Dưới đây là thông báo xác nhận quyền sở hữu bắt buộc trong nhóm thông báo xác nhận quyền sở hữu JWT. Các mã này có thể xuất hiện theo thứ tự bất kỳ trong thông báo xác nhận quyền sở hữu.

Tên Mô tả
iss Địa chỉ email của tài khoản dịch vụ.
scope Danh sách các quyền được phân tách bằng dấu cách mà ứng dụng yêu cầu.
aud Nhãn mô tả mục tiêu dự kiến của khẳng định. Khi yêu cầu mã truy cập, giá trị này luôn là https://oauth2.googleapis.com/token.
exp Thời gian hết hạn của lời khẳng định, được chỉ định là giây kể từ 00:00:00 giờ UTC, ngày 1 tháng 1 năm 1970. Giá trị này có tối đa 1 giờ sau thời gian phát hành.
iat Thời gian đưa ra tuyên bố, được chỉ định là giây kể từ 00:00:00 giờ UTC, ngày 1 tháng 1 năm 1970.

Dưới đây là phần trình bày JSON về các trường bắt buộc trong nhóm thông báo xác nhận quyền sở hữu JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Thông báo xác nhận quyền sở hữu bổ sung

Trong một số trường hợp doanh nghiệp, một ứng dụng có thể dùng tính năng ủy quyền trên toàn miền để thay mặt cho một người dùng cụ thể trong một tổ chức. Bạn phải được cấp quyền thực hiện hành vi mạo danh này trước khi ứng dụng có thể nhập vai người dùng và thường do quản trị viên cấp cao xử lý. Để biết thêm thông tin, hãy xem bài viết Kiểm soát quyền truy cập API với chế độ ủy quyền trên toàn miền.

Để có mã truy cập cấp cho một ứng dụng quyền truy cập vào một tài nguyên, hãy thêm địa chỉ email của người dùng vào thông báo xác nhận quyền sở hữu JWT đặt làm giá trị của trường sub.

Tên Mô tả
sub Địa chỉ email của người dùng mà ứng dụng đang yêu cầu quyền truy cập được ủy quyền.

Nếu một ứng dụng không có quyền nhập vai người dùng, thì phản hồi cho một yêu cầu mã truy cập có chứa trường sub sẽ là một lỗi.

Dưới đây là ví dụ về trường hợp xác nhận quyền sở hữu JWT bao gồm trường sub:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Mã hóa nhóm thông báo xác nhận quyền sở hữu JWT

Giống như tiêu đề JWT, tập hợp thông báo xác nhận quyền sở hữu JWT phải được chuyển đổi tuần tự thành UTF-8 và Base64url-safe gồm mã hóa. Dưới đây là ví dụ về cách biểu diễn JSON của tập hợp khiếu nại JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
Điện toán chữ ký

Chữ ký web JSON (JWS) là thông số kỹ thuật hướng dẫn cơ chế tạo chữ ký cho JWT. Đầu vào cho chữ ký là mảng byte của nội dung sau:

{Base64url encoded header}.{Base64url encoded claim set}

Thuật toán ký trong tiêu đề JWT phải được sử dụng khi tính toán chữ ký. Thuật toán ký duy nhất mà Máy chủ ủy quyền Google OAuth 2.0 hỗ trợ là RSA bằng thuật toán băm SHA-256. URL này được biểu thị bằng RS256 trong trường alg trong tiêu đề JWT.

Ký hiệu biểu thị UTF-8 của đầu vào bằng cách sử dụng SHA256withRSA (còn được gọi là RSASSA-PKCS1-V1_5-SIGN với hàm băm SHA-256) bằng khóa riêng tư thu được từ Google API Console. Đầu ra sẽ là một mảng byte.

Sau đó, chữ ký phải được mã hóa bằng Base64url. Tiêu đề, bộ thông báo xác nhận quyền sở hữu và chữ ký được nối với nhau bằng dấu chấm (.). Kết quả là JWT. Nội dung này phải là nội dung sau (dấu ngắt dòng được thêm cho rõ ràng):

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

Dưới đây là ví dụ về mã JWT trước khi mã hóa Base64url:

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

Dưới đây là ví dụ về một JWT đã được ký và sẵn sàng để truyền:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

Gửi yêu cầu mã thông báo truy cập

Sau khi tạo JWT đã ký, ứng dụng có thể sử dụng JWT đó để yêu cầu mã truy cập. Yêu cầu mã truy cập này là một yêu cầu HTTPS POST và nội dung được mã hóa URL. URL dưới đây:

https://oauth2.googleapis.com/token

Các thông số sau đây là bắt buộc trong yêu cầu HTTPS POST:

Tên Mô tả
grant_type Sử dụng chuỗi sau (được mã hóa URL nếu cần): urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JWT, bao gồm cả chữ ký.

Dưới đây là tệp kết xuất thô của yêu cầu POST HTTPS được dùng trong yêu cầu mã truy cập:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

Dưới đây là cùng yêu cầu đó, sử dụng curl:

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

Xử lý câu trả lời

Nếu yêu cầu mã truy cập và mã WWT được định dạng đúng cách và tài khoản dịch vụ có quyền thực hiện thao tác, thì phản hồi JSON từ Máy chủ ủy quyền sẽ bao gồm mã truy cập. Dưới đây là phản hồi mẫu:

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

Bạn có thể sử dụng lại mã truy cập trong khoảng thời gian do giá trị expires_in chỉ định.

Gọi API Google

Java

Hãy sử dụng đối tượng GoogleCredential để gọi các API của Google bằng cách hoàn thành các bước sau:

  1. Tạo một đối tượng dịch vụ cho API mà bạn muốn gọi bằng cách sử dụng đối tượng GoogleCredential. Ví dụ:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. Gửi yêu cầu tới dịch vụ API bằng giao diện do đối tượng dịch vụ cung cấp. Ví dụ: để liệt kê các phiên bản của cơ sở dữ liệu Cloud SQL trong dự án thú vị example-123:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

Sử dụng đối tượng Credentials được ủy quyền để gọi các API của Google bằng cách hoàn thành các bước sau:

  1. Tạo đối tượng dịch vụ cho API mà bạn muốn gọi. Bạn tạo một đối tượng dịch vụ bằng cách gọi hàm build có tên và phiên bản API và đối tượng Credentials được ủy quyền. Ví dụ: để gọi phiên bản 1 bản 3 của API quản trị Cloud SQL:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. Gửi yêu cầu tới dịch vụ API bằng giao diện do đối tượng dịch vụ cung cấp. Ví dụ: để liệt kê các phiên bản của cơ sở dữ liệu Cloud SQL trong dự án thú vị example-123:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST (Ngôn ngữ đánh dấu xác nhận bảo mật)

Sau khi ứng dụng của bạn nhận được mã truy cập, bạn có thể sử dụng mã đó để gọi điện đến API Google thay mặt cho một tài khoản dịch vụ hoặc tài khoản người dùng cụ thể nếu(các) phạm vi truy cập mà API yêu cầu đã cấp. Để làm điều này, hãy đưa mã truy cập vào yêu cầu API bằng cách thêm thông số truy vấn access_token hoặc tiêu đề Authorization tiêu đề HTTP Bearer. Khi có thể, bạn nên dùng tiêu đề HTTP vì các chuỗi truy vấn có xu hướng xuất hiện trong nhật ký máy chủ. Trong hầu hết trường hợp, bạn có thể sử dụng thư viện ứng dụng để thiết lập lệnh gọi đến API Google (ví dụ: khi gọi API Drive Files).

Bạn có thể dùng thử tất cả API của Google và xem phạm vi của các API này tại OAuth 2.0 Playground.

Ví dụ về HTTP GET

Lệnh gọi đến điểm cuối drive.files (API Drive Drive) bằng cách sử dụng tiêu đề HTTP Authorization: Bearer có thể có dạng như sau. Xin lưu ý rằng bạn cần chỉ định mã truy cập của riêng mình:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Dưới đây là lệnh gọi đến cùng một API cho người dùng đã xác thực bằng cách sử dụng thông số chuỗi truy vấn access_token:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

Ví dụ về curl

Bạn có thể kiểm tra các lệnh này bằng ứng dụng dòng lệnh curl. Sau đây là ví dụ về cách sử dụng tùy chọn tiêu đề HTTP (ưu tiên):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Hoặc tùy chọn tham số chuỗi truy vấn:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Khi mã thông báo truy cập hết hạn

Mã truy cập do Máy chủ ủy quyền Google OAuth 2.0 cấp sẽ hết hạn sau thời hạn do giá trị expires_in cung cấp. Khi mã truy cập hết hạn, ứng dụng đó sẽ tạo một WWT khác, ký và yêu cầu một mã truy cập khác.

Mã lỗi JWT

Trường error Trường error_description Ý nghĩa Cách giải quyết
unauthorized_client Unauthorized client or scope in request. Nếu bạn đang cố gắng dùng tính năng ủy quyền trên toàn miền, thì tài khoản dịch vụ sẽ không được ủy quyền trong Bảng điều khiển dành cho quản trị viên của miền của người dùng đó.

Đảm bảo rằng tài khoản dịch vụ được ủy quyền trong trang Ủy quyền trên toàn miền của Bảng điều khiển dành cho quản trị viên cho người dùng trong thông báo xác nhận quyền sở hữu sub (trường).

Mặc dù thường mất vài phút, nhưng cũng có thể mất tới 24 giờ để ủy quyền có hiệu lực cho tất cả người dùng trong Tài khoản Google của bạn.

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. Một tài khoản dịch vụ đã được cấp phép bằng địa chỉ email khách hàng thay vì mã ứng dụng (số) trong Bảng điều khiển dành cho quản trị viên. Trên trang Ủy quyền trên toàn miền trong Bảng điều khiển dành cho quản trị viên, hãy xóa máy khách rồi thêm lại bằng mã số đó.
access_denied (bất kỳ giá trị nào) Nếu bạn đang dùng tính năng ủy quyền trên toàn miền, thì một hoặc nhiều phạm vi được yêu cầu không được ủy quyền trong Bảng điều khiển dành cho quản trị viên.

Đảm bảo rằng tài khoản dịch vụ được ủy quyền trong trang Ủy quyền trên toàn miền của Bảng điều khiển dành cho quản trị viên cho người dùng trong thông báo xác nhận quyền sở hữu sub (trường) và bao gồm tất cả các phạm vi bạn đang yêu cầu trong thông báo xác nhận quyền sở hữu scope của JWT.

Mặc dù thường mất vài phút, nhưng cũng có thể mất tới 24 giờ để ủy quyền có hiệu lực cho tất cả người dùng trong Tài khoản Google của bạn.

invalid_grant Not a valid email. Người dùng không tồn tại. Kiểm tra để đảm bảo địa chỉ email trong thông báo xác nhận quyền sở hữu (trường) sub là chính xác.
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

Thông thường, điều đó có nghĩa là giờ hệ thống địa phương không chính xác. Việc này cũng có thể xảy ra nếu giá trị exp sau 65 phút kể từ giá trị iat, hoặc giá trị exp thấp hơn iat.

Đảm bảo rằng đồng hồ trên hệ thống tạo JWT là chính xác. Nếu cần, hãy đồng bộ hóa thời gian của bạn với Google NTP.

invalid_grant Invalid JWT Signature.

Lệnh xác nhận JWT được ký bằng một khóa riêng tư không liên kết với tài khoản dịch vụ được xác định qua email khách hàng hoặc khóa được sử dụng đã bị xóa, vô hiệu hóa hoặc đã hết hạn.

Ngoài ra, phương thức xác nhận JWT có thể được mã hóa không chính xác – phương thức này phải được mã hóa bằng Base64, không có dòng mới hoặc dấu bằng.

Giải mã tập hợp xác nhận quyền sở hữu JWT và xác minh khóa đã ký xác nhận liên kết với tài khoản dịch vụ.

Hãy thử dùng thư viện OAuth do Google cung cấp để đảm bảo JWT được tạo chính xác.

invalid_scope Invalid OAuth scope or ID token audience provided. Không có phạm vi nào được yêu cầu (danh sách phạm vi trống) hoặc một trong các phạm vi đã yêu cầu không tồn tại (tức là không hợp lệ).

Hãy đảm bảo rằng bạn xác nhận quyền sở hữu scope (trường) của JWT và so sánh các phạm vi mà trường này chứa với phạm vi đã xác định cho các API mà bạn muốn sử dụng để đảm bảo không có lỗi hoặc lỗi chính tả.

Xin lưu ý rằng danh sách các phạm vi trong thông báo xác nhận quyền sở hữu scope cần được phân tách bằng dấu cách, không phải dấu phẩy.

disabled_client The OAuth client was disabled. Khóa dùng để ký xác nhận JWT đã bị tắt.

Truy cập vào Google API Consolevà trong mục IAM & Admin > Account Accounts, hãy bật tài khoản dịch vụ có chứa "Key ID" dùng để ký khẳng định.

Phụ lục: Ủy quyền tài khoản dịch vụ không có OAuth

Với một số API của Google, bạn có thể thực hiện các lệnh gọi API được ủy quyền bằng cách sử dụng JWT đã ký trực tiếp dưới dạng mã thông báo truy cập, thay vì mã truy cập OAuth 2.0. Nếu có thể, bạn có thể tránh được việc phải gửi yêu cầu mạng đến máy chủ ủy quyền của Google trước khi thực hiện lệnh gọi API.

Nếu API bạn muốn gọi có định nghĩa dịch vụ được xuất bản trong kho lưu trữ GitHub của Google API, bạn có thể thực hiện các lệnh gọi API được ủy quyền bằng cách sử dụng JWT thay vì mã truy cập. Cách thực hiện:

  1. Tạo một tài khoản dịch vụ như mô tả ở trên. Hãy nhớ giữ lại tệp JSON mà bạn nhận được khi tạo tài khoản.
  2. Sử dụng một thư viện JWT chuẩn, chẳng hạn như một thư viện tại jwt.io, tạo một WWT có tiêu đề và phần dữ liệu thực tế như ví dụ sau:
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • Đối với trường kid trong tiêu đề, hãy chỉ định mã khóa riêng tư của tài khoản dịch vụ. Bạn có thể tìm thấy giá trị này trong trường private_key_id của tệp JSON chứa tài khoản dịch vụ.
    • Đối với các trường isssub, hãy chỉ định địa chỉ email của tài khoản dịch vụ. Bạn có thể tìm thấy giá trị này trong trường client_email của tệp JSON chứa tài khoản dịch vụ.
    • Đối với trường aud, hãy chỉ định điểm cuối API. Ví dụ:https://SERVICE.googleapis.com/
    • Đối với trường iat, hãy chỉ định thời gian Unix hiện tại và đối với trường exp, hãy chỉ định thời gian chính xác 3600 giây sau đó, thì JWT sẽ hết hạn.

Ký JWT bằng RSA-256 bằng khoá riêng tư có trong tệp JSON của tài khoản dịch vụ.

Ví dụ:

Java

Dùng google-api-java-clientjava-jwt:

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

Sử dụng PyJWT:

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. Gọi API, sử dụng JWT đã ký làm mã thông báo truy cập:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com