OAuth 2.0 cho Ứng dụng web phía máy khách

Tài liệu này giải thích cách triển khai ủy quyền OAuth 2.0 để truy cập API Google từ ứng dụng web JavaScript. OAuth 2.0 cho phép người dùng chia sẻ dữ liệu cụ thể với một ứng dụng trong khi vẫn bảo mật tên người dùng, mật khẩu và các thông tin khác. Ví dụ: một ứng dụng có thể sử dụng OAuth 2.0 để có được quyền của người dùng khi lưu trữ tệp trong Google Drive.

Quy trình OAuth 2.0 này được gọi là quy trình cấp quyền ngầm ẩn. API này được thiết kế cho các ứng dụng chỉ truy cập API khi người dùng có mặt tại ứng dụng. Các ứng dụng này không thể lưu trữ thông tin mật.

Trong quy trình này, ứng dụng của bạn sẽ mở một URL Google sử dụng các tham số truy vấn để xác định ứng dụng và loại quyền truy cập API mà ứng dụng yêu cầu. Bạn có thể mở URL trong cửa sổ trình duyệt hiện tại hoặc một cửa sổ bật lên. Người dùng có thể xác thực với Google và cấp các quyền được yêu cầu. Sau đó, Google sẽ chuyển hướng người dùng quay lại ứng dụng của bạn. Quá trình chuyển hướng bao gồm một mã truy cập mà ứng dụng xác minh rồi sử dụng để đưa ra các yêu cầu API.

Thư viện ứng dụng API của Google và Dịch vụ nhận dạng của Google

Nếu sử dụng Thư viện ứng dụng API Google cho JavaScript để thực hiện các lệnh gọi được ủy quyền đến Google, bạn nên sử dụng thư viện JavaScript Dịch vụ danh tính của Google để xử lý quy trình OAuth 2.0. Vui lòng xem mô hình mã thông báo của Dịch vụ nhận dạng của Google dựa trên luồng ngầm ẩn cấp quyền OAuth 2.0.

Điều kiện tiên quyết

Bật API cho dự án của bạn

Mọi ứng dụng gọi API của Google đều cần bật những API đó trong API Console.

Cách bật API cho dự án:

  1. Open the API Library trong Google API Console.
  2. If prompted, select a project, or create a new one.
  3. API Library Liệt kê tất cả những API có sẵn, được nhóm theo nhóm sản phẩm và mức độ phổ biến. Nếu API bạn muốn bật không hiển thị trong danh sách, hãy sử dụng chức năng tìm kiếm để tìm API đó hoặc nhấp vào View All (Xem tất cả) trong nhóm sản phẩm chứa API đó.
  4. Chọn API bạn muốn bật, sau đó nhấp vào nút Bật.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

Tạo thông tin xác thực ủy quyền

Bất kỳ ứng dụng nào sử dụng OAuth 2.0 để truy cập API Google đều phải có thông tin đăng nhập ủy quyền để xác định ứng dụng với máy chủ OAuth 2.0 của Google. Các bước sau giải thích cách tạo thông tin xác thực cho dự án của bạn. Sau đó, các ứng dụng của bạn có thể dùng thông tin đăng nhập để truy cập vào các API mà bạn đã bật cho dự án đó.

  1. Go to the Credentials page.
  2. Nhấp vào Tạo thông tin xác thực > Mã ứng dụng khách OAuth.
  3. Chọn loại ứng dụng Web application.
  4. Hoàn thành biểu mẫu. Các ứng dụng dùng JavaScript để gửi các yêu cầu API Google được ủy quyền phải chỉ định các nguồn gốc JavaScript được ủy quyền. Nguồn gốc xác định miền mà từ đó ứng dụng của bạn có thể gửi yêu cầu đến máy chủ OAuth 2.0. Các nguồn gốc này phải tuân thủ quy tắc xác thực của Google.

Xác định phạm vi truy cập

Phạm vi cho phép ứng dụng của bạn chỉ yêu cầu quyền truy cập vào tài nguyên cần thiết trong khi cũng cho phép người dùng kiểm soát số lượng quyền truy cập mà họ cấp vào ứng dụng của bạn. Do đó, có thể có mối quan hệ nghịch đảo giữa số lượng phạm vi được yêu cầu và khả năng lấy được sự đồng ý của người dùng.

Trước khi bắt đầu triển khai việc cấp quyền OAuth 2.0, bạn nên xác định các phạm vi mà ứng dụng của mình sẽ cần quyền truy cập.

Tài liệu về Phạm vi API OAuth 2.0 chứa danh sách đầy đủ các phạm vi mà bạn có thể dùng để truy cập API Google.

Lấy mã truy cập OAuth 2.0

Các bước sau cho thấy cách ứng dụng tương tác với máy chủ OAuth 2.0 của Google để lấy sự đồng ý của người dùng thay mặt người dùng thực hiện yêu cầu API. Ứng dụng phải có được sự đồng ý đó trước khi có thể thực thi một yêu cầu API của Google có yêu cầu phải có sự cho phép của người dùng.

Bước 1: Chuyển hướng đến máy chủ OAuth 2.0 của Google

Để yêu cầu quyền truy cập vào dữ liệu của một người dùng, hãy chuyển hướng người dùng đó đến máy chủ OAuth 2.0 của Google.

Điểm cuối OAuth 2.0

Tạo một URL để yêu cầu quyền truy cập từ điểm cuối OAuth 2.0 của Google tại https://accounts.google.com/o/oauth2/v2/auth. Bạn có thể truy cập điểm cuối này qua HTTPS; các kết nối HTTP đơn giản bị từ chối.

Máy chủ uỷ quyền của Google hỗ trợ các tham số chuỗi truy vấn sau đây cho các ứng dụng máy chủ web:

Thông số
client_id Bắt buộc

Mã ứng dụng khách cho ứng dụng của bạn. Bạn có thể tìm thấy giá trị này trong API Console Credentials page.

redirect_uri Bắt buộc

Xác định nơi máy chủ API chuyển hướng người dùng sau khi người dùng hoàn tất quy trình uỷ quyền. Giá trị này phải khớp chính xác với một trong các URI chuyển hướng được uỷ quyền cho ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong API Console Credentials pagecủa ứng dụng. Nếu giá trị này không khớp với một URI chuyển hướng được uỷ quyền cho client_id đã cung cấp, thì bạn sẽ gặp lỗi redirect_uri_mismatch.

Xin lưu ý rằng giao thức http hoặc https, chữ hoa và dấu gạch chéo ('/') đều phải khớp.

response_type Bắt buộc

Ứng dụng JavaScript cần đặt giá trị của tham số thành token. Giá trị này chỉ dẫn Máy chủ uỷ quyền của Google trả về mã truy cập dưới dạng một cặp name=value trong giá trị nhận dạng phân đoạn của URI (#) mà người dùng được chuyển hướng đến sau khi hoàn tất quy trình uỷ quyền.

scope Bắt buộc

Danh sách phạm vi được phân tách bằng dấu cách xác định tài nguyên mà ứng dụng của bạn có thể thay mặt người dùng truy cập. Những giá trị này thông báo cho người dùng về màn hình xin phép mà Google hiển thị.

Phạm vi cho phép ứng dụng của bạn chỉ yêu cầu quyền truy cập vào tài nguyên cần thiết, đồng thời cho phép người dùng kiểm soát số lượng quyền truy cập mà họ cấp vào ứng dụng của bạn. Do đó, có mối quan hệ nghịch đảo giữa số lượng phạm vi được yêu cầu và khả năng lấy được sự đồng ý của người dùng.

Ứng dụng nên yêu cầu quyền truy cập vào các phạm vi uỷ quyền theo ngữ cảnh bất cứ khi nào có thể. Bằng cách yêu cầu quyền truy cập vào dữ liệu người dùng trong bối cảnh, thông qua ủy quyền gia tăng, bạn giúp người dùng hiểu lý do tại sao ứng dụng cần quyền truy cập mà ứng dụng đó yêu cầu.

state Recommended (Nên dùng)

Chỉ định mọi giá trị chuỗi mà ứng dụng dùng để duy trì trạng thái giữa yêu cầu uỷ quyền và phản hồi của máy chủ uỷ quyền. Máy chủ trả về giá trị chính xác mà bạn gửi dưới dạng một cặp name=value trong giá trị nhận dạng phân đoạn URL (#) của redirect_uri sau khi người dùng đồng ý hoặc từ chối yêu cầu truy cập của ứng dụng.

Bạn có thể sử dụng thông số này cho nhiều mục đích, chẳng hạn như chuyển hướng người dùng đến đúng tài nguyên trong ứng dụng, gửi số chỉ dùng một lần và giảm thiểu hành vi giả mạo yêu cầu trên nhiều trang web. Vì redirect_uri có thể được đoán, nên việc sử dụng giá trị state có thể giúp đảm bảo rằng một kết nối đến là kết quả của một yêu cầu xác thực. Nếu tạo một chuỗi ngẫu nhiên hoặc mã hóa giá trị băm của một cookie hoặc một giá trị khác nắm bắt trạng thái của ứng dụng khách, thì bạn có thể xác thực phản hồi để đảm bảo rằng yêu cầu và phản hồi đó bắt nguồn trong cùng một trình duyệt, bảo vệ trước các cuộc tấn công như giả mạo yêu cầu trên nhiều trang web. Hãy xem tài liệu về OpenID Connect để biết ví dụ về cách tạo và xác nhận mã thông báo state.

include_granted_scopes Optional (Không bắt buộc)

Cho phép các ứng dụng dùng lệnh ủy quyền gia tăng để yêu cầu quyền truy cập vào các phạm vi bổ sung trong ngữ cảnh. Nếu bạn đặt giá trị của tham số này thành true và yêu cầu cấp quyền đã được cấp, thì mã truy cập mới cũng sẽ bao gồm mọi phạm vi mà trước đó người dùng đã cấp quyền truy cập vào ứng dụng. Hãy xem mục ủy quyền gia tăng để biết ví dụ.

login_hint Optional (Không bắt buộc)

Nếu biết được người dùng nào đang cố xác thực, thì ứng dụng của bạn có thể dùng tham số này để gợi ý cho Máy chủ xác thực của Google. Máy chủ sử dụng gợi ý để đơn giản hóa luồng đăng nhập bằng cách điền trước trường email trong biểu mẫu đăng nhập hoặc bằng cách chọn phiên đăng nhập nhiều tài khoản thích hợp.

Đặt giá trị tham số thành một địa chỉ email hoặc giá trị nhận dạng sub, tương đương với mã Google của người dùng.

prompt Optional (Không bắt buộc)

Danh sách lời nhắc phân tách bằng dấu cách, phân biệt chữ hoa chữ thường để hiển thị cho người dùng. Nếu bạn không chỉ định thông số này, người dùng sẽ chỉ được nhắc trong lần đầu tiên dự án của bạn yêu cầu quyền truy cập. Hãy xem bài viết Nhắc đồng ý lại để biết thêm thông tin.

Các giá trị có thể là:

none Không hiển thị màn hình xác thực hoặc sự đồng ý. Không được chỉ định bằng các giá trị khác.
consent Nhắc người dùng đồng ý.
select_account Nhắc người dùng chọn tài khoản.

Mẫu chuyển hướng đến máy chủ uỷ quyền của Google

URL ví dụ được hiển thị bên dưới, có ngắt dòng và khoảng trắng cho dễ đọc.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

Sau khi bạn tạo URL yêu cầu, hãy chuyển hướng người dùng đến URL đó.

Mã mẫu JavaScript

Đoạn mã JavaScript sau đây cho biết cách bắt đầu quy trình ủy quyền trong JavaScript mà không cần sử dụng Thư viện ứng dụng API của Google cho JavaScript. Vì điểm cuối OAuth 2.0 này không hỗ trợ tính năng Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS) nên đoạn mã sẽ tạo một biểu mẫu để mở yêu cầu tới điểm cuối đó.

/*
 * 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 <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_REDIRECT_URI',
                '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();
}

Bước 2: Google nhắc người dùng đồng ý

Ở bước này, người dùng quyết định có cấp cho ứng dụng của bạn quyền truy cập đã yêu cầu hay không. Ở giai đoạn này, Google sẽ hiển thị một cửa sổ lấy sự đồng ý hiển thị tên ứng dụng của bạn và các dịch vụ API của Google mà Google đang yêu cầu quyền truy cập bằng thông tin đăng nhập của người dùng cùng một bản tóm tắt phạm vi quyền truy cập sẽ được cấp. Sau đó, người dùng có thể đồng ý cấp quyền truy cập vào một hoặc nhiều phạm vi mà ứng dụng của bạn yêu cầu hoặc từ chối yêu cầu.

Ứng dụng của bạn không cần làm gì ở giai đoạn này vì đang chờ phản hồi từ máy chủ OAuth 2.0 của Google cho biết liệu có quyền truy cập nào hay không. Bước phản hồi sẽ được giải thích trong bước sau.

Lỗi

Các yêu cầu đến điểm cuối ủy quyền OAuth 2.0 của Google có thể hiển thị thông báo lỗi cho người dùng thay vì quy trình xác thực và ủy quyền dự kiến. Dưới đây là danh sách các mã lỗi phổ biến và độ phân giải đề xuất.

admin_policy_enforced

Tài khoản Google không thể ủy quyền cho một hoặc nhiều phạm vi được yêu cầu theo chính sách của quản trị viên Google Workspace. Xem bài viết trợ giúp dành cho Quản trị viên Google Workspace Kiểm soát những ứng dụng nội bộ và ứng dụng bên thứ ba nào truy cập vào dữ liệu Google Workspace để biết thêm thông tin về cách quản trị viên có thể hạn chế quyền truy cập vào tất cả các phạm vi hoặc các phạm vi nhạy cảm và bị hạn chế cho đến khi bạn cấp quyền truy cập cho mã ứng dụng khách OAuth một cách rõ ràng.

disallowed_useragent

Điểm cuối ủy quyền được hiển thị bên trong tác nhân người dùng được nhúng theo Chính sách OAuth 2.0 của Google.

Android

Nhà phát triển Android có thể gặp thông báo lỗi này khi mở yêu cầu ủy quyền trong android.webkit.WebView. Thay vào đó, nhà phát triển nên sử dụng các thư viện Android như Đăng nhập bằng Google cho Android hoặc AppAuth cho Android của OpenID Foundation.

Các nhà phát triển web có thể gặp lỗi này khi ứng dụng Android mở một đường liên kết web chung trong một tác nhân người dùng được nhúng và người dùng chuyển đến điểm cuối ủy quyền OAuth 2.0 của Google từ trang web của bạn. Nhà phát triển nên cho phép các đường liên kết chung mở trong trình xử lý đường liên kết mặc định của hệ điều hành, bao gồm cả trình xử lý Đường liên kết trong ứng dụng Android hoặc ứng dụng trình duyệt mặc định. Bạn cũng có thể sử dụng thư viện Thẻ tuỳ chỉnh của Android.

iOS

Nhà phát triển iOS và macOS có thể gặp lỗi này khi mở yêu cầu cấp quyền trong WKWebView. Thay vào đó, nhà phát triển nên sử dụng các thư viện iOS như Đăng nhập bằng Google cho iOS hoặc AppAuth cho iOS của OpenID Foundation.

Các nhà phát triển web có thể gặp lỗi này khi ứng dụng iOS hoặc macOS mở một đường liên kết web chung trong một tác nhân người dùng được nhúng và người dùng truy cập vào điểm cuối ủy quyền OAuth 2.0 của Google từ trang web của bạn. Nhà phát triển nên cho phép mở các đường liên kết chung trong trình xử lý đường liên kết mặc định của hệ điều hành, bao gồm cả trình xử lý Đường liên kết chung hoặc ứng dụng trình duyệt mặc định. Bạn cũng có thể sử dụng thư viện SFSafariViewController.

org_internal

Mã ứng dụng khách OAuth trong yêu cầu này là một phần của dự án hạn chế quyền truy cập vào Tài khoản Google trong một tổ chức cụ thể của Google Cloud. Để biết thêm thông tin về tuỳ chọn cấu hình này, hãy xem phần Loại người dùng trong bài viết trợ giúp Thiết lập màn hình đồng ý OAuth.

invalid_client

Nguồn gốc mà từ đó yêu cầu được đưa ra không được phép cho ứng dụng này. Hãy xem origin_mismatch.

invalid_grant

Khi sử dụng ủy quyền gia tăng, mã thông báo có thể đã hết hạn hoặc đã bị vô hiệu hóa. Xác thực lại người dùng và yêu cầu người dùng đồng ý lấy mã thông báo mới. Nếu bạn vẫn thấy lỗi này, hãy đảm bảo ứng dụng của bạn được định cấu hình chính xác và bạn đang sử dụng đúng mã thông báo cũng như thông số trong yêu cầu. Nếu không, tài khoản người dùng có thể đã bị xóa hoặc vô hiệu hóa.

origin_mismatch

Lược đồ, miền và/hoặc cổng của JavaScript khởi tạo yêu cầu ủy quyền có thể không khớp với URI gốc của JavaScript đã được đăng ký cho mã ứng dụng khách OAuth. Xem các nguồn gốc JavaScript được cho phép trong Google API Console Credentials page.

redirect_uri_mismatch

redirect_uri đã chuyển trong yêu cầu uỷ quyền không khớp với một URI chuyển hướng uỷ quyền cho mã ứng dụng khách OAuth. Xem xét các URI chuyển hướng được uỷ quyền trong Google API Console Credentials page.

Lược đồ, miền và/hoặc cổng của JavaScript khởi tạo yêu cầu ủy quyền có thể không khớp với URI gốc của JavaScript đã được đăng ký cho mã ứng dụng khách OAuth. Xem xét các nguồn gốc JavaScript được cho phép trong Google API Console Credentials page.

Tham số redirect_uri có thể tham chiếu đến luồng ngoài băng tần (OOB) OAuth đã ngừng hoạt động và không còn được hỗ trợ. Hãy tham khảo hướng dẫn di chuyển để cập nhật nội dung tích hợp.

Bước 3: Xử lý phản hồi của máy chủ OAuth 2.0

Điểm cuối OAuth 2.0

Máy chủ OAuth 2.0 sẽ gửi phản hồi tới redirect_uri được chỉ định trong yêu cầu mã truy cập.

Nếu người dùng chấp thuận yêu cầu, thì phản hồi sẽ chứa mã truy cập. Nếu người dùng không phê duyệt yêu cầu, thì phản hồi sẽ chứa thông báo lỗi. Mã thông báo truy cập hoặc thông báo lỗi được trả về trên mảnh băm của URI chuyển hướng, như hiển thị dưới đây:

  • Phản hồi của mã thông báo truy cập:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    Ngoài tham số access_token, chuỗi mảnh còn chứa tham số token_type, luôn được đặt thành Bearer và tham số expires_in chỉ định thời gian tồn tại của mã thông báo tính bằng giây. Nếu tham số state được chỉ định trong yêu cầu mã thông báo truy cập, thì giá trị của tham số đó cũng sẽ được đưa vào phản hồi.

  • Phản hồi lỗi:
    https://oauth2.example.com/callback#error=access_denied

Phản hồi máy chủ OAuth 2.0 mẫu

Bạn có thể kiểm tra quy trình này bằng cách nhấp vào URL mẫu sau. URL này yêu cầu quyền chỉ có thể đọc để xem siêu dữ liệu cho các tệp trong Google Drive của bạn:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

Sau khi hoàn tất quy trình OAuth 2.0, bạn sẽ được chuyển hướng đến http://localhost/oauth2callback. URL đó sẽ gây ra lỗi 404 NOT FOUND trừ phi máy cục bộ của bạn tình cờ phân phát một tệp tại địa chỉ đó. Bước tiếp theo sẽ cung cấp thêm thông tin chi tiết về thông tin được trả về trong URI khi người dùng được chuyển hướng trở lại ứng dụng của bạn.

Gọi API Google

Điểm cuối OAuth 2.0

Sau khi ứng dụng của bạn lấy được mã truy cập, bạn có thể sử dụng mã thông báo này để thực hiện lệnh gọi đến API Google thay mặt cho một tài khoản người dùng cụ thể nếu(các) phạm vi quyền truy cập mà API đó yêu cầu đã được cấp. Để thực hiện việc này, hãy đưa mã truy cập vào một yêu cầu tới API bằng cách đưa vào một tham số truy vấn access_token hoặc một giá trị Bearer tiêu đề HTTP Authorization. Khi có thể, bạn nên ưu tiên tiêu đề HTTP hơn vì các chuỗi truy vấn thường hiển thị 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 các API của Google (ví dụ: khi gọi API Tệp Drive).

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

Ví dụ về HTTP GET

Lệnh gọi đến điểm cuối drive.files (API Tệp Drive) bằ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 tham 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 thử các lệnh này bằng ứng dụng dòng lệnh curl. Dưới đây là ví dụ về cách sử dụng tuỳ chọn tiêu đề HTTP (ưu tiên):

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

Hoặc, có thể là, tùy chọn tham số chuỗi truy vấn:

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

Mã mẫu JavaScript

Đoạn mã dưới đây minh hoạ cách sử dụng CORS (Chia sẻ tài nguyên trên nhiều nguồn gốc) để gửi yêu cầu đến API Google. Ví dụ này không sử dụng Thư viện ứng dụng API của Google dành cho JavaScript. Tuy nhiên, ngay cả khi bạn không sử dụng thư viện ứng dụng, hướng dẫn hỗ trợ CORS trong tài liệu của thư viện đó cũng có thể giúp bạn hiểu rõ hơn về các yêu cầu này.

Trong đoạn mã này, biến access_token đại diện cho mã thông báo mà bạn nhận được để thực hiện các yêu cầu API thay mặt người dùng được ủy quyền. Ví dụ hoàn chỉnh minh hoạ cách lưu trữ mã thông báo đó trong bộ nhớ cục bộ của trình duyệt và truy xuất mã đó khi thực hiện yêu cầu API.

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) {
  console.log(xhr.response);
};
xhr.send(null);

Ví dụ đầy đủ

Điểm cuối OAuth 2.0

Mã mẫu này minh họa cách hoàn tất luồng OAuth 2.0 trong JavaScript mà không cần sử dụng Thư viện ứng dụng API của Google dành cho JavaScript. Mã này dành cho một trang HTML hiển thị một nút để thử yêu cầu API. Nếu bạn nhấp vào nút này, mã sẽ kiểm tra xem trang có lưu trữ mã truy cập API trong bộ nhớ cục bộ của trình duyệt hay không. Nếu có, API này sẽ thực thi yêu cầu API. Nếu không, hệ thống sẽ bắt đầu quy trình OAuth 2.0.

Đối với quy trình OAuth 2.0, trang sẽ làm theo các bước sau:

  1. Thao tác này sẽ chuyển người dùng đến máy chủ OAuth 2.0 của Google để yêu cầu quyền truy cập vào phạm vi https://www.googleapis.com/auth/drive.metadata.readonly.
  2. Sau khi cấp (hoặc từ chối) quyền truy cập vào một hoặc nhiều phạm vi yêu cầu, người dùng sẽ được chuyển hướng đến trang gốc. Thẻ này sẽ phân tích cú pháp mã truy cập trong chuỗi giá trị nhận dạng mảnh.
  3. Trang sử dụng mã truy cập để tạo yêu cầu API mẫu.

    Yêu cầu API gọi phương thức about.get của API Drive để truy xuất thông tin về tài khoản Google Drive của người dùng được uỷ quyền.

  4. Nếu yêu cầu được thực thi thành công, thì phản hồi API sẽ được ghi vào bảng điều khiển gỡ lỗi của trình duyệt.

Bạn có thể thu hồi quyền truy cập của ứng dụng thông qua trang Quyền trong Tài khoản Google của mình. Ứng dụng sẽ được liệt kê là Bản trình diễn OAuth 2.0 cho Google Tài liệu API.

Để chạy mã này trên máy, bạn cần đặt giá trị cho các biến YOUR_CLIENT_IDYOUR_REDIRECT_URI tương ứng với thông tin đăng nhập uỷ quyền. Bạn nên đặt biến YOUR_REDIRECT_URI thành cùng một URL mà trang đang được phân phát. Giá trị này phải khớp chính xác với một trong các URI chuyển hướng được uỷ quyền cho ứng dụng OAuth 2.0 mà bạn đã định cấu hình trong API Console Credentials page. Nếu giá trị này không khớp với một URI được uỷ quyền, bạn sẽ gặp lỗi redirect_uri_mismatch. Dự án của bạn cũng phải bật API phù hợp cho yêu cầu này.

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

Quy tắc xác thực nguồn gốc JavaScript

Google áp dụng các quy tắc xác thực sau cho nguồn gốc JavaScript để giúp nhà phát triển bảo mật ứng dụng của họ. Nguồn gốc JavaScript của bạn phải tuân thủ các quy tắc này. Hãy xem RFC 3986 phần 3 để biết định nghĩa về miền, máy chủ và giao thức được đề cập bên dưới.

Các quy tắc xác thực
Lược đồ

Nguồn gốc JavaScript phải sử dụng lược đồ HTTPS, không phải HTTP thuần túy. URI máy chủ cục bộ (bao gồm URI địa chỉ IP máy chủ cục bộ) được miễn khỏi quy tắc này.

Người dẫn chương trình

Máy chủ không thể là địa chỉ IP thô. Địa chỉ IP máy chủ cục bộ được miễn khỏi quy tắc này.

Miền
  • Miền cấp cao nhất (TLD) lưu trữ (Miền cấp cao nhất) phải thuộc danh sách hậu tố công khai.
  • Miền của máy chủ không thể là “googleusercontent.com”.
  • Nguồn gốc JavaScript không được chứa miền rút gọn URL (ví dụ: goo.gl) trừ phi ứng dụng này sở hữu miền.
  • Thông tin người dùng

    Nguồn gốc JavaScript không thể chứa thành phần phụ userinfo.

    Đường dẫn

    Nguồn gốc JavaScript không thể chứa thành phần đường dẫn.

    Cụm từ tìm kiếm

    Nguồn gốc JavaScript không thể chứa thành phần truy vấn.

    Mảnh

    Nguồn gốc JavaScript không được chứa thành phần mảnh.

    Ký tự Nguồn gốc JavaScript không được chứa các ký tự nhất định, bao gồm:
    • Ký tự đại diện ('*')
    • Ký tự ASCII không thể in được
    • Phương thức mã hóa phần trăm không hợp lệ (bất kỳ phương thức mã hóa phần trăm nào không theo dạng mã hóa URL của ký hiệu phần trăm theo sau là hai chữ số thập lục phân)
    • Ký tự rỗng (ký tự NULL được mã hóa, ví dụ: %00, %C0%80)

    Ủy quyền tăng dần

    Trong giao thức OAuth 2.0, ứng dụng sẽ yêu cầu ủy quyền truy cập vào các tài nguyên được xác định theo phạm vi. Phương pháp hay nhất về trải nghiệm người dùng là yêu cầu ủy quyền cho các tài nguyên tại thời điểm bạn cần. Để cho phép thực hiện việc này, máy chủ uỷ quyền của Google sẽ hỗ trợ uỷ quyền tăng dần. Tính năng này cho phép bạn yêu cầu phạm vi khi cần và nếu người dùng cấp quyền cho phạm vi mới, sẽ trả về một mã ủy quyền có thể được trao đổi để lấy mã thông báo chứa tất cả các phạm vi mà người dùng đã cấp dự án.

    Ví dụ: một ứng dụng cho phép mọi người lấy mẫu bản nhạc và tạo danh sách kết hợp có thể cần rất ít tài nguyên tại thời điểm đăng nhập, có thể chỉ là tên của người đăng nhập. Tuy nhiên, để lưu một danh sách kết hợp đã hoàn thành, bạn cần có quyền truy cập vào Google Drive. Hầu hết mọi người sẽ thấy điều này là tự nhiên nếu họ chỉ được yêu cầu quyền truy cập vào Google Drive vào thời điểm ứng dụng thực sự cần quyền đó.

    Trong trường hợp này, tại thời điểm đăng nhập, ứng dụng có thể yêu cầu phạm vi openidprofile để đăng nhập cơ bản, sau đó yêu cầu phạm vi https://www.googleapis.com/auth/drive.file tại thời điểm yêu cầu đầu tiên lưu danh sách kết hợp.

    Các quy tắc sau áp dụng cho mã thông báo truy cập thu được từ ủy quyền gia tăng:

    • Bạn có thể sử dụng mã thông báo này để truy cập vào các tài nguyên tương ứng với bất kỳ phạm vi nào thuộc uỷ quyền kết hợp mới.
    • Khi bạn sử dụng mã làm mới cho uỷ quyền kết hợp để lấy mã truy cập, mã truy cập sẽ đại diện cho uỷ quyền kết hợp và có thể dùng cho bất kỳ giá trị scope nào có trong phản hồi.
    • Ủy quyền kết hợp bao gồm tất cả các phạm vi mà người dùng đã cấp cho dự án API ngay cả khi các ứng dụng khác nhau đã yêu cầu tài trợ. Ví dụ: nếu người dùng cấp quyền truy cập vào một phạm vi bằng ứng dụng khách dành cho máy tính của một ứng dụng, sau đó cấp một phạm vi khác cho cùng một ứng dụng đó thông qua ứng dụng di động, thì lệnh uỷ quyền kết hợp sẽ bao gồm cả hai phạm vi.
    • Nếu bạn thu hồi một mã thông báo biểu thị một lệnh ủy quyền kết hợp, thì quyền truy cập vào tất cả các phạm vi của tài khoản ủy quyền đó thay mặt cho người dùng được liên kết sẽ bị thu hồi đồng thời.

    Các mã mẫu dưới đây cho biết cách thêm phạm vi vào mã truy cập hiện có. Phương pháp này cho phép ứng dụng của bạn không phải quản lý nhiều mã truy cập.

    Điểm cuối OAuth 2.0

    Để thêm phạm vi vào mã thông báo truy cập hiện có, hãy đưa thông số include_granted_scopes vào yêu cầu của bạn tới máy chủ OAuth 2.0 của Google.

    Đoạn mã sau đây minh hoạ cách làm việc đó. Đoạn mã giả định rằng bạn đã lưu trữ các phạm vi mà mã truy cập của bạn hợp lệ trong bộ nhớ cục bộ của trình duyệt. (Mã ví dụ đầy đủ lưu trữ danh sách các phạm vi mà mã truy cập hợp lệ bằng cách đặt thuộc tính oauth2-test-params.scope trong bộ nhớ cục bộ của trình duyệt.)

    Đoạn mã này so sánh các phạm vi mà mã truy cập hợp lệ với phạm vi mà bạn muốn sử dụng cho một truy vấn cụ thể. Nếu mã thông báo truy cập không bao gồm phạm vi đó, luồng OAuth 2.0 sẽ bắt đầu. Ở đây, hàm oauth2SignIn giống với hàm được cung cấp trong bước 2 (và được cung cấp sau trong ví dụ đầy đủ).

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

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

    Trong một số trường hợp, người dùng có thể muốn thu hồi quyền truy cập đã cấp cho ứng dụng. Người dùng có thể thu hồi quyền truy cập bằng cách truy cập vào phần Cài đặt tài khoản. Vui lòng xem tài liệu hỗ trợ Xóa trang web hoặc ứng dụng của các trang web và ứng dụng của bên thứ ba có quyền truy cập vào tài khoản của bạn để biết thêm thông tin.

    Ứng dụng cũng có thể thu hồi quyền truy cập đã cấp cho ứng dụng theo phương thức lập trình. Thu hồi có lập trình có ý nghĩa quan trọng trong trường hợp người dùng hủy đăng ký, xóa một ứng dụng hoặc tài nguyên API mà ứng dụng yêu cầu đã thay đổi đáng kể. Nói cách khác, một phần của quy trình xóa có thể bao gồm một yêu cầu API để đảm bảo những quyền trước đây đã cấp cho ứng dụng bị xóa.

    Điểm cuối OAuth 2.0

    Để thu hồi mã thông báo theo phương thức lập trình, ứng dụng sẽ gửi yêu cầu đến https://oauth2.googleapis.com/revoke và bao gồm mã thông báo dưới dạng thông số:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    Đây có thể là mã truy cập hoặc mã làm mới. Nếu mã này là mã truy cập và có mã làm mới tương ứng, mã làm mới cũng sẽ bị thu hồi.

    Nếu quá trình thu hồi được xử lý thành công, thì mã trạng thái HTTP của phản hồi sẽ là 200. Đối với các điều kiện lỗi, mã trạng thái HTTP 400 sẽ được trả về cùng với mã lỗi.

    Đoạn mã JavaScript sau đây cho biết cách thu hồi một mã thông báo trong JavaScript mà không cần sử dụng Thư viện ứng dụng API của Google cho JavaScript. Vì điểm cuối OAuth 2.0 của Google để thu hồi mã thông báo không hỗ trợ Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS) nên mã sẽ tạo một biểu mẫu và gửi biểu mẫu đến điểm cuối thay vì sử dụng phương thức XMLHttpRequest() để đăng yêu cầu.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }