การใช้ OAuth 2.0 สำหรับแอปพลิเคชันระหว่างเซิร์ฟเวอร์กับเซิร์ฟเวอร์

ระบบ OAuth 2.0 ของ Google รองรับการโต้ตอบระหว่างเซิร์ฟเวอร์ เช่น การโต้ตอบระหว่างแอปพลิเคชันเว็บกับบริการของ Google ในกรณีนี้ คุณต้องมีบัญชีบริการ ซึ่งเป็นบัญชีของแอปพลิเคชัน ไม่ใช่ของผู้ใช้ปลายทางแต่ละราย แอปพลิเคชันจะเรียกใช้ Google APIs ในนามบัญชีบริการนั้น ผู้ใช้จึงไม่มีส่วนเกี่ยวข้องโดยตรง บางครั้งสถานการณ์นี้เรียกว่า "OAuth แบบ 2 ฝ่าย" หรือ "2LO" (คําที่เกี่ยวข้อง "OAuth แบบ 3 ทาง" หมายถึงสถานการณ์ที่แอปพลิเคชันเรียกใช้ Google APIs ในนามของผู้ใช้ปลายทาง และบางครั้งต้องได้รับความยินยอมจากผู้ใช้)

โดยปกติแล้ว แอปพลิเคชันจะใช้บัญชีบริการเมื่อแอปพลิเคชันใช้ Google API เพื่อทำงานกับข้อมูลของตนเองแทนข้อมูลของผู้ใช้ ตัวอย่างเช่น แอปพลิเคชันที่ใช้ Google Cloud Datastore สำหรับการคงข้อมูลไว้จะใช้บัญชีบริการเพื่อตรวจสอบสิทธิ์การเรียกใช้ Google Cloud Datastore API

นอกจากนี้ ผู้ดูแลระบบโดเมน Google Workspace ยังให้สิทธิ์ทั่วทั้งโดเมนแก่บัญชีบริการเพื่อเข้าถึงข้อมูลผู้ใช้ในนามของผู้ใช้โดเมนได้ด้วย

เอกสารนี้อธิบายวิธีที่แอปพลิเคชันสามารถทําตามโฟลว์ OAuth 2.0 แบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ให้เสร็จสมบูรณ์ได้โดยใช้ไลบรารีไคลเอ็นต์ Google APIs (แนะนำ) หรือ HTTP

ภาพรวม

หากต้องการรองรับการโต้ตอบระหว่างเซิร์ฟเวอร์ ก่อนอื่นให้สร้างบัญชีบริการสําหรับโปรเจ็กต์ใน หากต้องการเข้าถึงข้อมูลผู้ใช้ในบัญชี Google Workspace ให้มอบสิทธิ์เข้าถึงทั่วทั้งโดเมนแก่บัญชีบริการ

จากนั้นแอปพลิเคชันจะเตรียมการเรียก API ที่มีสิทธิ์โดยใช้ข้อมูลเข้าสู่ระบบของบัญชีบริการเพื่อขอโทเค็นการเข้าถึงจากเซิร์ฟเวอร์การตรวจสอบสิทธิ์ OAuth 2.0

สุดท้าย แอปพลิเคชันจะใช้โทเค็นการเข้าถึงเพื่อเรียกใช้ Google API ได้

การสร้างบัญชีบริการ

ข้อมูลเข้าสู่ระบบของบัญชีบริการประกอบด้วยอีเมลที่สร้างขึ้นซึ่งไม่ซ้ำกัน และคู่คีย์สาธารณะ/คีย์ส่วนตัวอย่างน้อย 1 คู่ หากเปิดใช้การมอบสิทธิ์ทั่วทั้งโดเมน รหัสไคลเอ็นต์ก็จะเป็นส่วนหนึ่งของข้อมูลเข้าสู่ระบบของบัญชีบริการด้วย

หากแอปพลิเคชันของคุณทำงานบน Google App Engine ระบบจะตั้งค่าบัญชีบริการโดยอัตโนมัติเมื่อคุณสร้างโปรเจ็กต์

หากแอปพลิเคชันของคุณทำงานบน Google Compute Engine ระบบจะตั้งค่าบัญชีบริการโดยอัตโนมัติเมื่อคุณสร้างโปรเจ็กต์ แต่คุณต้องระบุขอบเขตที่แอปพลิเคชันของคุณจำเป็นต้องเข้าถึงเมื่อสร้างอินสแตนซ์ Google Compute Engine ดูข้อมูลเพิ่มเติมได้ที่การเตรียมอินสแตนซ์ให้ใช้บัญชีบริการ

หากแอปพลิเคชันของคุณไม่ทํางานบน Google App Engine หรือ Google Compute Engine คุณต้องรับข้อมูลเข้าสู่ระบบเหล่านี้ใน หากต้องการสร้างข้อมูลเข้าสู่ระบบของบัญชีบริการหรือดูข้อมูลเข้าสู่ระบบสาธารณะที่คุณสร้างไว้แล้ว ให้ทําดังนี้

คุณกลับมาที่ ได้ทุกเมื่อเพื่อดูอีเมล ลายนิ้วมือของคีย์สาธารณะ และข้อมูลอื่นๆ หรือเพื่อสร้างคู่คีย์สาธารณะ/ส่วนตัวเพิ่มเติม โปรดดูรายละเอียดเพิ่มเติมเกี่ยวกับข้อมูลเข้าสู่ระบบของบัญชีบริการใน ที่หัวข้อบัญชีบริการใน ไฟล์ความช่วยเหลือ

จดบันทึกอีเมลของบัญชีบริการและจัดเก็บไฟล์คีย์ส่วนตัวของบัญชีบริการไว้ในตำแหน่งที่แอปพลิเคชันเข้าถึงได้ แอปพลิเคชันของคุณต้องใช้โทเค็นเหล่านี้เพื่อทำการเรียก API ที่ได้รับอนุญาต

การมอบสิทธิ์ทั่วทั้งโดเมนให้กับบัญชีบริการ

เมื่อใช้บัญชี Google Workspace ผู้ดูแลระบบ Workspace ขององค์กรสามารถให้สิทธิ์แอปพลิเคชันเข้าถึงข้อมูลผู้ใช้ Workspace ในนามของผู้ใช้ในโดเมน Google Workspace ได้ ตัวอย่างเช่น แอปพลิเคชันที่ใช้ Google Calendar API เพื่อเพิ่มกิจกรรมในปฏิทินของผู้ใช้ทั้งหมดในโดเมน Google Workspace จะใช้บัญชีบริการเพื่อเข้าถึง Google Calendar API ในนามของผู้ใช้ การให้สิทธิ์บัญชีบริการเข้าถึงข้อมูลในนามของผู้ใช้ในโดเมนบางครั้งเรียกว่า "การมอบสิทธิ์ทั่วทั้งโดเมน" ให้กับบัญชีบริการ

หากต้องการมอบสิทธิ์ทั่วทั้งโดเมนให้กับบัญชีบริการ ผู้ดูแลระบบขั้นสูงของโดเมน Google Workspace ต้องทำตามขั้นตอนต่อไปนี้

  1. จาก คอนโซลผู้ดูแลระบบของโดเมน Google Workspace ให้ไปที่เมนูหลัก > ความปลอดภัย > การเข้าถึงและการควบคุมข้อมูล > การควบคุม API
  2. ในแผงการมอบสิทธิ์ทั่วทั้งโดเมน ให้เลือกจัดการการมอบสิทธิ์ทั่วทั้งโดเมน
  3. คลิกเพิ่มใหม่
  4. กรอกรหัสไคลเอ็นต์ของบัญชีบริการในช่องรหัสไคลเอ็นต์ คุณสามารถดูรหัสไคลเอ็นต์ของบัญชีบริการได้ใน
  5. ในช่องขอบเขต OAuth (คั่นด้วยคอมมา) ให้ป้อนรายการขอบเขตที่แอปพลิเคชันควรได้รับสิทธิ์เข้าถึง เช่น หากแอปพลิเคชันต้องการสิทธิ์เข้าถึง Google Drive API และ Google Calendar API แบบทั่วทั้งโดเมนโดยสมบูรณ์ ให้ป้อนข้อมูลดังนี้ https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar
  6. คลิกให้สิทธิ์

ตอนนี้แอปพลิเคชันของคุณมีสิทธิ์เรียก API ในฐานะผู้ใช้ในโดเมน Workspace (เพื่อ "แอบอ้างเป็น" ผู้ใช้) เมื่อเตรียมที่จะเรียก API ที่มอบสิทธิ์เหล่านี้ คุณจะระบุผู้ใช้ที่จะแอบอ้างเป็นอย่างชัดเจน

เตรียมการเรียก API ที่มอบสิทธิ์

Java

หลังจากได้รับอีเมลและคีย์ส่วนตัวของลูกค้าจาก แล้ว ให้ใช้ไลบรารีของไคลเอ็นต์ Google APIs สำหรับ Java เพื่อสร้างออบเจ็กต์ GoogleCredential จากข้อมูลเข้าสู่ระบบของบัญชีบริการและขอบเขตที่แอปพลิเคชันของคุณจำเป็นต้องเข้าถึง เช่น

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

หากกำลังพัฒนาแอปใน Google Cloud Platform คุณสามารถใช้ข้อมูลเข้าสู่ระบบเริ่มต้นของแอปพลิเคชันแทน ซึ่งจะทำให้กระบวนการง่ายขึ้น

มอบสิทธิ์ทั่วทั้งโดเมน

หากคุณมอบสิทธิ์การเข้าถึงทั้งโดเมนให้กับบัญชีบริการและต้องการแอบอ้างเป็นบัญชีผู้ใช้ ให้ระบุอีเมลของบัญชีผู้ใช้ด้วยเมธอด createDelegated ของออบเจ็กต์ GoogleCredential เช่น

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

โค้ดด้านบนใช้ออบเจ็กต์ GoogleCredential เพื่อเรียกใช้เมธอด createDelegated() อาร์กิวเมนต์สำหรับเมธอด createDelegated() ต้องเป็นผู้ใช้ที่เป็นของบัญชี Workspace โค้ดที่ส่งคําขอจะใช้ข้อมูลเข้าสู่ระบบนี้เพื่อเรียกใช้ Google API โดยใช้บัญชีบริการของคุณ

Python

หลังจากได้รับอีเมลและคีย์ส่วนตัวของลูกค้าจาก แล้ว ให้ใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับ Python เพื่อทำตามขั้นตอนต่อไปนี้

  1. สร้างออบเจ็กต์ Credentials จากข้อมูลเข้าสู่ระบบของบัญชีบริการและขอบเขตที่แอปพลิเคชันของคุณจำเป็นต้องเข้าถึง เช่น
    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)

    หากกำลังพัฒนาแอปใน Google Cloud Platform คุณสามารถใช้ข้อมูลเข้าสู่ระบบเริ่มต้นของแอปพลิเคชันแทน ซึ่งจะทำให้กระบวนการง่ายขึ้น

  2. มอบสิทธิ์ทั่วทั้งโดเมน

    หากคุณมอบสิทธิ์การเข้าถึงทั้งโดเมนให้กับบัญชีบริการและต้องการแอบอ้างเป็นบัญชีผู้ใช้ ให้ใช้เมธอด with_subject ของออบเจ็กต์ ServiceAccountCredentials ที่มีอยู่ เช่น

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

ใช้ออบเจ็กต์ข้อมูลเข้าสู่ระบบเพื่อเรียกใช้ Google APIs ในแอปพลิเคชัน

HTTP/REST

หลังจากได้รับรหัสไคลเอ็นต์และคีย์ส่วนตัวจาก แล้ว แอปพลิเคชันของคุณจะต้องทําตามขั้นตอนต่อไปนี้

  1. สร้างโทเค็นเว็บ JSON (JWT ซึ่งออกเสียงว่า "jot") ซึ่งมีส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็น
  2. ขอโทเค็นการเข้าถึงจากเซิร์ฟเวอร์การให้สิทธิ์ OAuth 2.0 ของ Google
  3. จัดการการตอบกลับ JSON ที่เซิร์ฟเวอร์การให้สิทธิ์แสดง

ส่วนต่อไปนี้จะอธิบายวิธีดำเนินการตามขั้นตอนเหล่านี้

หากการตอบกลับมีโทเค็นการเข้าถึง คุณจะใช้โทเค็นการเข้าถึงเพื่อเรียกใช้ Google API ได้ (หากคำตอบไม่มีโทเค็นการเข้าถึง แสดงว่า JWT และคำขอโทเค็นอาจอยู่ในรูปแบบที่ไม่ถูกต้อง หรือบัญชีบริการอาจไม่มีสิทธิ์เข้าถึงขอบเขตที่ขอ)

เมื่อโทเค็นการเข้าถึงหมดอายุ แอปพลิเคชันจะสร้าง JWT รายการอื่น ลงนาม และขอโทเค็นการเข้าถึงรายการอื่น

แอปพลิเคชันเซิร์ฟเวอร์ใช้ JWT เพื่อขอโทเค็นจากเซิร์ฟเวอร์การให้สิทธิ์ของ Google จากนั้นใช้โทเค็นเพื่อเรียกใช้ปลายทาง Google API ไม่มีผู้ใช้ปลายทางที่เกี่ยวข้อง

ส่วนที่เหลือของส่วนนี้จะอธิบายรายละเอียดการสร้าง JWT, การเซ็นชื่อ JWT, การสร้างคําขอโทเค็นการเข้าถึง และการจัดการคําตอบ

การสร้าง JWT

JWT ประกอบด้วย 3 ส่วน ได้แก่ ส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็น ส่วนหัวและชุดการอ้างสิทธิ์คือออบเจ็กต์ JSON ออบเจ็กต์ JSON เหล่านี้จะได้รับการแปลงเป็นอนุกรมไบต์ UTF-8 จากนั้นเข้ารหัสโดยใช้การเข้ารหัส Base64url ซึ่งการเข้ารหัสนี้มีความยืดหยุ่นต่อการเปลี่ยนแปลงการเข้ารหัสเนื่องจากการดำเนินการเข้ารหัสซ้ำๆ ส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็นจะต่อเชื่อมกันด้วยอักขระจุด (.)

JWT ประกอบด้วยส่วนต่างๆ ดังนี้

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

สตริงฐานสําหรับลายเซ็นมีดังนี้

{Base64url encoded header}.{Base64url encoded claim set}
การสร้างส่วนหัว JWT

ส่วนหัวประกอบด้วย 3 ช่องที่ระบุอัลกอริทึมการลงชื่อ รูปแบบของข้อความยืนยัน และ [รหัสคีย์ของคีย์บัญชีบริการ](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys) ที่ใช้ลงชื่อ JWT คุณต้องระบุอัลกอริทึมและรูปแบบ และแต่ละช่องจะมีเพียงค่าเดียว เมื่อมีการเปิดตัวอัลกอริทึมและรูปแบบเพิ่มเติม ส่วนหัวนี้จะเปลี่ยนแปลงไปตามความเหมาะสม รหัสคีย์เป็นตัวเลือก หากระบุรหัสคีย์ที่ไม่ถูกต้อง GCP จะพยายามใช้คีย์ทั้งหมดที่เชื่อมโยงกับบัญชีบริการเพื่อยืนยันโทเค็นและปฏิเสธโทเค็นหากไม่พบคีย์ที่ถูกต้อง Google ขอสงวนสิทธิ์ในการปฏิเสธโทเค็นที่มีรหัสคีย์ไม่ถูกต้องในอนาคต

บัญชีบริการใช้อัลกอริทึม RSA SHA-256 และรูปแบบโทเค็น JWT ด้วยเหตุนี้ การแสดง JSON ของส่วนหัวจึงมีดังนี้

{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}

การนําเสนอ Base64url ของข้อมูลนี้คือ

          eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
การสร้างชุดการอ้างสิทธิ์ JWT

ชุดการอ้างสิทธิ์ JWT มีข้อมูลเกี่ยวกับ JWT รวมถึงสิทธิ์ที่ขอ (ขอบเขต) เป้าหมายของโทเค็น ผู้ออกโทเค็น เวลาออกโทเค็น และอายุของโทเค็น คุณต้องกรอกข้อมูลในช่องส่วนใหญ่ ชุดการอ้างสิทธิ์ JWT จะเป็นออบเจ็กต์ JSON เช่นเดียวกับส่วนหัว JWT และใช้ในการคำนวณลายเซ็น

การอ้างสิทธิ์ที่จำเป็น

ข้อมูลอ้างอิงที่จําเป็นในชุดข้อมูลอ้างอิง JWT แสดงอยู่ด้านล่าง โดยอาจปรากฏในชุดการอ้างสิทธิ์ตามลำดับใดก็ได้

ชื่อ คำอธิบาย
iss อีเมลของบัญชีบริการ
scope รายการสิทธิ์ที่แอปพลิเคชันขอโดยคั่นด้วยเว้นวรรค
aud ตัวบ่งชี้เป้าหมายที่ต้องการของการยืนยัน เมื่อสร้างคำขอโทเค็นการเข้าถึง ค่านี้จะเท่ากับ https://oauth2.googleapis.com/token เสมอ
exp เวลาหมดอายุของการยืนยัน ซึ่งระบุเป็นวินาทีนับจาก 00:00:00 UTC วันที่ 1 มกราคม 1970 ค่านี้มีระยะเวลาสูงสุด 1 ชั่วโมงหลังจากเวลาที่ออก
iat เวลาที่มีการออกการยืนยัน ซึ่งระบุเป็นวินาทีนับจาก 00:00:00 UTC วันที่ 1 มกราคม 1970

การแสดง JSON ของช่องที่ต้องกรอกในชุดการอ้างสิทธิ์ 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
}
การอ้างสิทธิ์เพิ่มเติม

ในบางกรณีสำหรับองค์กร แอปพลิเคชันสามารถใช้การมอบสิทธิ์ทั่วทั้งโดเมนเพื่อดำเนินการในนามของผู้ใช้รายใดรายหนึ่งในองค์กร สิทธิ์ในการดำเนินการแอบอ้างเป็นบุคคลอื่นประเภทนี้ต้องได้รับอนุญาตก่อนแอปพลิเคชันจะแอบอ้างเป็นผู้ใช้ได้ และโดยปกติแล้วผู้ดูแลระบบขั้นสูงจะเป็นผู้จัดการ ดูข้อมูลเพิ่มเติมได้ที่ควบคุมการเข้าถึง API ด้วยการมอบสิทธิ์ทั่วทั้งโดเมน

หากต้องการรับโทเค็นการเข้าถึงที่ให้สิทธิ์เข้าถึงที่มอบสิทธิ์แก่แอปพลิเคชันไปยังแหล่งข้อมูล ให้ใส่อีเมลของผู้ใช้ไว้ในชุดการอ้างสิทธิ์ JWT เป็นค่าของช่อง sub

ชื่อ คำอธิบาย
sub อีเมลของผู้ใช้ที่แอปพลิเคชันขอสิทธิ์เข้าถึงที่มอบสิทธิ์

หากแอปพลิเคชันไม่มีสิทธิ์ในการแอบอ้างเป็นผู้ใช้ การตอบกลับคำขอโทเค็นการเข้าถึงที่มีช่อง sub จะแสดงข้อผิดพลาด

ตัวอย่างชุดการอ้างสิทธิ์ JWT ที่มีช่อง 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
}
การเข้ารหัสชุดการอ้างสิทธิ์ JWT

ชุดการอ้างสิทธิ์ JWT ควรจัดรูปแบบเป็น UTF-8 และเข้ารหัส Base64url-safe เช่นเดียวกับส่วนหัว JWT ด้านล่างนี้คือตัวอย่างการนําเสนอ JSON ของชุดการอ้างสิทธิ์ JWT

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
การคํานวณลายเซ็น

JSON Web Signature (JWS) คือข้อกำหนดที่แนะนำกลไกการสร้างลายเซ็นสำหรับ JWT อินพุตสำหรับลายเซ็นคืออาร์เรย์ไบต์ของเนื้อหาต่อไปนี้

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

ต้องใช้อัลกอริทึมการลงนามในส่วนหัว JWT เมื่อคํานวณลายเซ็น อัลกอริทึมการเซ็นชื่อเพียงอัลกอริทึมเดียวที่เซิร์ฟเวอร์การให้สิทธิ์ OAuth 2.0 ของ Google รองรับคือ RSA โดยใช้อัลกอริทึมการแฮช SHA-256 ซึ่งจะแสดงเป็น RS256 ในช่อง alg ในส่วนหัวของ JWT

ลงนามการนำเสนอ UTF-8 ของอินพุตโดยใช้ SHA256withRSA (หรือที่เรียกว่า RSASSA-PKCS1-V1_5-SIGN ที่มีฟังก์ชันแฮช SHA-256) ด้วยคีย์ส่วนตัวที่ได้รับจาก ผลลัพธ์จะเป็นอาร์เรย์ไบต์

จากนั้นต้องเข้ารหัสลายเซ็นเป็น Base64url ส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็นจะต่อเชื่อมกันด้วยอักขระจุด (.) ผลลัพธ์ที่ได้คือ JWT โดยควรมีลักษณะดังต่อไปนี้ (มีการเพิ่มการแบ่งบรรทัดเพื่อความชัดเจน)

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

ด้านล่างนี้คือตัวอย่าง JWT ก่อนการเข้ารหัส 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]

ด้านล่างนี้คือตัวอย่าง JWT ที่ลงนามแล้วและพร้อมสำหรับการส่ง

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

การส่งคําขอโทเค็นการเข้าถึง

หลังจากสร้าง JWT ที่ลงชื่อแล้ว แอปพลิเคชันจะใช้ JWT ดังกล่าวเพื่อขอโทเค็นการเข้าถึงได้ คำขอโทเค็นการเข้าถึงนี้เป็นคำขอ POST ของ HTTPS และเนื้อหาได้รับการเข้ารหัส URL URL แสดงอยู่ด้านล่าง

https://oauth2.googleapis.com/token

พารามิเตอร์ต่อไปนี้ต้องระบุในคําขอ POST ของ HTTPS

ชื่อ คำอธิบาย
grant_type ใช้สตริงต่อไปนี้ซึ่งเข้ารหัส URL ตามที่จำเป็น urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JWT รวมถึงลายเซ็น

ด้านล่างนี้คือข้อมูลการพุลดิบของคำขอ POST ผ่าน HTTPS ที่ใช้ในคำขอโทเค็นการเข้าถึง

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

ด้านล่างนี้คือคําขอเดียวกันที่ใช้ 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

การจัดการคำตอบ

หาก JWT และคำขอโทเค็นการเข้าถึงมีรูปแบบถูกต้องและบัญชีบริการมีสิทธิ์ดำเนินการ การตอบกลับ JSON จากเซิร์ฟเวอร์การให้สิทธิ์จะมีโทเค็นการเข้าถึง ตัวอย่างคำตอบมีดังนี้

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

คุณใช้โทเค็นการเข้าถึงซ้ำได้ในช่วงระยะเวลาที่ระบุโดยค่า expires_in

การเรียกใช้ Google API

Java

ใช้ออบเจ็กต์ GoogleCredential เพื่อเรียกใช้ Google APIs โดยทําตามขั้นตอนต่อไปนี้

  1. สร้างออบเจ็กต์บริการสําหรับ API ที่ต้องการเรียกใช้โดยใช้ออบเจ็กต์ GoogleCredential เช่น
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. ส่งคําขอไปยังบริการ API โดยใช้อินเทอร์เฟซที่ออบเจ็กต์บริการระบุ เช่น หากต้องการแสดงรายการอินสแตนซ์ของฐานข้อมูล Cloud SQL ในโปรเจ็กต์ exciting-example-123 ให้ทำดังนี้
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

ใช้ออบเจ็กต์ Credentials ที่ได้รับอนุญาตเพื่อเรียกใช้ Google APIs โดยทําตามขั้นตอนต่อไปนี้

  1. สร้างออบเจ็กต์บริการสําหรับ API ที่ต้องการเรียกใช้ คุณสร้างออบเจ็กต์บริการโดยเรียกใช้ฟังก์ชัน build พร้อมชื่อและเวอร์ชันของ API รวมถึงออบเจ็กต์ Credentials ที่ได้รับอนุญาต เช่น หากต้องการเรียกใช้ Cloud SQL Administration API เวอร์ชัน 1beta3 ให้ทำดังนี้
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. ส่งคําขอไปยังบริการ API โดยใช้อินเทอร์เฟซที่ออบเจ็กต์บริการระบุ เช่น หากต้องการแสดงรายการอินสแตนซ์ของฐานข้อมูล Cloud SQL ในโปรเจ็กต์ exciting-example-123 ให้ทำดังนี้
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

หลังจากแอปพลิเคชันได้รับโทเค็นการเข้าถึงแล้ว คุณจะใช้โทเค็นดังกล่าวเพื่อเรียกใช้ Google API ในนามของบัญชีบริการหรือบัญชีผู้ใช้ที่ระบุได้ หากได้รับสิทธิ์เข้าถึงตามขอบเขตที่ API กำหนด โดยใส่โทเค็นการเข้าถึงในคำขอไปยัง API โดยใส่พารามิเตอร์การค้นหา access_token หรือค่าส่วนหัว HTTP Authorization Bearer หากเป็นไปได้ เราขอแนะนำให้ใช้ส่วนหัว HTTP เนื่องจากสตริงการค้นหามีแนวโน้มที่จะปรากฏในบันทึกของเซิร์ฟเวอร์ ในกรณีส่วนใหญ่ คุณสามารถใช้ไลบรารีของไคลเอ็นต์เพื่อตั้งค่าการเรียกใช้ Google API (เช่น เมื่อเรียกใช้ Drive Files API)

คุณสามารถลองใช้ Google API ทั้งหมดและดูขอบเขตของ API เหล่านั้นได้ที่ OAuth 2.0 Playground

ตัวอย่าง HTTP GET

การเรียกใช้ปลายทาง drive.files (Drive Files API) โดยใช้ส่วนหัว HTTP ของ Authorization: Bearer อาจมีลักษณะดังนี้ โปรดทราบว่าคุณต้องระบุโทเค็นการเข้าถึงของคุณเอง โดยทำดังนี้

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

นี่คือการเรียก API เดียวกันสําหรับผู้ใช้ที่ตรวจสอบสิทธิ์แล้วโดยใช้พารามิเตอร์สตริงการค้นหา access_token

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

ตัวอย่างของ curl

คุณสามารถทดสอบคําสั่งเหล่านี้ด้วยแอปพลิเคชันบรรทัดคําสั่ง curl ต่อไปนี้คือตัวอย่างที่ใช้ตัวเลือกส่วนหัว HTTP (แนะนำ)

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

หรือจะใช้ตัวเลือกพารามิเตอร์สตริงการค้นหาก็ได้

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

เมื่อโทเค็นการเข้าถึงหมดอายุ

โทเค็นการเข้าถึงที่ออกโดยเซิร์ฟเวอร์การให้สิทธิ์ OAuth 2.0 ของ Google จะหมดอายุหลังจากระยะเวลาที่ระบุโดยค่า expires_in เมื่อโทเค็นการเข้าถึงหมดอายุ แอปพลิเคชันควรสร้าง JWT ใหม่ ลงนาม และขอโทเค็นการเข้าถึงใหม่

รหัสข้อผิดพลาด JWT

error ฟิลด์ error_description ฟิลด์ ความหมาย วิธีแก้ไข
unauthorized_client Unauthorized client or scope in request. หากคุณพยายามใช้การมอบสิทธิ์ทั่วทั้งโดเมน บัญชีบริการไม่ได้รับสิทธิ์ในคอนโซลผู้ดูแลระบบของโดเมนผู้ใช้

ตรวจสอบว่าบัญชีบริการได้รับสิทธิ์ในหน้า การมอบสิทธิ์ทั่วทั้งโดเมนของคอนโซลผู้ดูแลระบบสำหรับผู้ใช้ในsubการอ้างสิทธิ์ (ช่อง)

แม้ว่าโดยปกติจะใช้เวลาเพียงไม่กี่นาที แต่อาจใช้เวลาถึง 24 ชั่วโมงเพื่อให้การให้สิทธิ์มีผลกับผู้ใช้ทุกคนในบัญชี Google

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. บัญชีบริการได้รับสิทธิ์โดยใช้อีเมลไคลเอ็นต์แทนรหัสไคลเอ็นต์ (ตัวเลข) ในคอนโซลผู้ดูแลระบบ ในหน้า การมอบสิทธิ์ทั่วทั้งโดเมนในคอนโซลผู้ดูแลระบบ ให้นำไคลเอ็นต์ออก แล้วเพิ่มอีกครั้งด้วยรหัสตัวเลข
access_denied (ค่าใดก็ได้) หากคุณใช้การมอบสิทธิ์ทั่วทั้งโดเมน ขอบเขตที่ขออย่างน้อย 1 รายการไม่ได้รับสิทธิ์ในคอนโซลผู้ดูแลระบบ

ตรวจสอบว่าบัญชีบริการได้รับสิทธิ์ในหน้า การมอบสิทธิ์ทั่วทั้งโดเมนของคอนโซลผู้ดูแลระบบสำหรับผู้ใช้ในข้อความอ้างสิทธิ์ sub (ช่อง) และบัญชีบริการดังกล่าวมีขอบเขตทั้งหมดที่คุณขอในข้อความอ้างสิทธิ์ scope ของ JWT

แม้ว่าโดยปกติจะใช้เวลาเพียงไม่กี่นาที แต่อาจใช้เวลาถึง 24 ชั่วโมงเพื่อให้การให้สิทธิ์มีผลกับผู้ใช้ทุกคนในบัญชี Google

admin_policy_enforced (ค่าใดก็ได้) บัญชี Google ไม่สามารถให้สิทธิ์ขอบเขตอย่างน้อย 1 รายการที่ขอเนื่องจากนโยบายของผู้ดูแลระบบ Google Workspace

โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ผู้ดูแลระบบอาจจำกัดการเข้าถึงขอบเขตทั้งหมดหรือขอบเขตที่มีความละเอียดอ่อนและถูกจํากัดจนกว่าจะมีการให้สิทธิ์เข้าถึงรหัสไคลเอ็นต์ OAuth ของคุณอย่างชัดเจนที่บทความความช่วยเหลือสําหรับผู้ดูแลระบบ Google Workspace เรื่องควบคุมว่าจะให้แอปของบุคคลที่สามและแอปภายในรายการใดเข้าถึงข้อมูล Google Workspace ได้บ้าง

invalid_client (ค่าใดก็ได้)

ไคลเอ็นต์ OAuth หรือโทเค็น JWT ไม่ถูกต้องหรือกําหนดค่าไม่ถูกต้อง

โปรดดูรายละเอียดในคำอธิบายข้อผิดพลาด

ตรวจสอบว่าโทเค็น JWT ถูกต้องและมีข้อมูลอ้างสิทธิ์ที่ถูกต้อง

ตรวจสอบว่าไคลเอ็นต์ OAuth และบัญชีบริการได้รับการกําหนดค่าอย่างถูกต้องและคุณใช้อีเมลที่ถูกต้อง

ตรวจสอบว่าโทเค็น JWT ถูกต้องและออกให้สำหรับรหัสไคลเอ็นต์ในคำขอ

invalid_grant Not a valid email. ไม่พบผู้ใช้ ตรวจสอบว่าอีเมลในsubการอ้างสิทธิ์ (ช่อง) ถูกต้อง
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.

ซึ่งโดยปกติแล้วหมายความว่าเวลาของระบบในเครื่องไม่ถูกต้อง หรืออาจเกิดขึ้นหากค่า exp อยู่ในอนาคตมากกว่า 65 นาทีจากค่า iat หรือค่า exp ต่ำกว่าค่า iat

ตรวจสอบว่านาฬิกาในระบบที่สร้าง JWT ถูกต้อง หากจำเป็น ให้ซิงค์เวลากับ NTP ของ Google

invalid_grant Invalid JWT Signature.

การยืนยัน JWT ลงชื่อด้วยคีย์ส่วนตัวที่ไม่ได้เชื่อมโยงกับบัญชีบริการที่ระบุโดยอีเมลไคลเอ็นต์ หรือคีย์ที่ใช้ถูกลบ ปิดใช้ หรือหมดอายุแล้ว

หรือการยืนยัน JWT อาจเข้ารหัสไม่ถูกต้อง และต้องเข้ารหัส Base64 โดยไม่มีบรรทัดใหม่หรือเครื่องหมายเท่ากับที่เติมไว้

ถอดรหัสชุดการอ้างสิทธิ์ JWT และตรวจสอบว่าคีย์ที่ลงนามในข้อความยืนยันเชื่อมโยงกับบัญชีบริการ

ลองใช้ไลบรารี OAuth ที่ Google มีให้เพื่อให้แน่ใจว่า JWT สร้างขึ้นอย่างถูกต้อง

invalid_scope Invalid OAuth scope or ID token audience provided. ไม่มีคำขอขอบเขต (รายการขอบเขตว่าง) หรือขอบเขตที่ขอไม่อยู่ (กล่าวคือไม่ถูกต้อง)

ตรวจสอบว่าได้ป้อนข้อมูลการอ้างสิทธิ์ scope (ช่อง) ของ JWT แล้ว และเปรียบเทียบขอบเขตที่มีกับขอบเขตที่บันทึกไว้สำหรับ API ที่ต้องการใช้เพื่อให้แน่ใจว่าไม่มีข้อผิดพลาดหรือการพิมพ์ผิด

โปรดทราบว่ารายการขอบเขตในการอ้างสิทธิ์ scope ต้องคั่นด้วยเว้นวรรค ไม่ใช่เครื่องหมายคอมมา

disabled_client The OAuth client was disabled. คีย์ที่ใช้ลงนามในข้อความยืนยัน JWT ถูกปิดใช้

ไปที่ และในส่วน IAM และผู้ดูแลระบบ > บัญชีบริการ ให้เปิดใช้บัญชีบริการที่มี "รหัสคีย์" ที่ใช้ลงนามในข้อความยืนยัน

org_internal This client is restricted to users within its organization. รหัสไคลเอ็นต์ OAuth ในคำขอเป็นส่วนหนึ่งของโปรเจ็กต์ที่จำกัดการเข้าถึงบัญชี Google ใน องค์กร Google Cloud ที่เฉพาะเจาะจง

ใช้บัญชีบริการจากองค์กรเพื่อตรวจสอบสิทธิ์ ยืนยันการกำหนดค่าประเภทผู้ใช้สำหรับแอปพลิเคชัน OAuth

ภาคผนวก: การให้สิทธิ์บัญชีบริการโดยไม่ใช้ OAuth

Google API บางรายการช่วยให้คุณเรียก API ที่มีสิทธิ์ได้โดยใช้ JWT ที่ลงนามแล้วโดยตรงเป็นโทเค็นของผู้ถือแทนโทเค็นการเข้าถึง OAuth 2.0 ซึ่งจะช่วยให้คุณไม่ต้องส่งคําขอเครือข่ายไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google ก่อนทำการเรียก API

หาก API ที่ต้องการเรียกมีคำจำกัดความของบริการที่เผยแพร่ในที่เก็บ GitHub ของ Google APIs คุณจะเรียก API ที่มีสิทธิ์ได้โดยใช้ JWT แทนโทเค็นการเข้าถึง โดยทำดังนี้

  1. สร้างบัญชีบริการตามที่อธิบายไว้ข้างต้น โปรดเก็บไฟล์ JSON ที่ได้รับเมื่อสร้างบัญชีไว้
  2. ใช้ไลบรารี JWT มาตรฐาน เช่น ไลบรารีที่พบใน jwt.io สร้าง JWT ที่มีส่วนหัวและเพย์โหลดดังตัวอย่างต่อไปนี้
    {
      "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
    }
    • สำหรับช่อง kid ในส่วนหัว ให้ระบุรหัสคีย์ส่วนตัวของบัญชีบริการ คุณดูค่านี้ได้ในช่อง private_key_id ของไฟล์ JSON ของบัญชีบริการ
    • สำหรับช่อง iss และ sub ให้ระบุอีเมลของบัญชีบริการ คุณดูค่านี้ได้ในช่อง client_email ของไฟล์ JSON ของบัญชีบริการ
    • สำหรับช่อง aud ให้ระบุปลายทาง API ตัวอย่างเช่น https://SERVICE.googleapis.com/
    • สําหรับช่อง iat ให้ระบุเวลา Unix ปัจจุบัน และสำหรับช่อง exp ให้ระบุเวลาหลังจากนั้น 3600 วินาทีโดยประมาณ ซึ่งเป็นเวลาที่ JWT จะหมดอายุ

ลงนาม JWT ด้วย RSA-256 โดยใช้คีย์ส่วนตัวที่อยู่ในไฟล์ JSON ของบัญชีบริการ

เช่น

Java

การใช้ google-api-java-client และ java-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

การใช้ 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. เรียก API โดยใช้ JWT ที่ลงชื่อเป็นโทเค็นผู้ถือดังต่อไปนี้
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com

การใช้การป้องกันแบบครอบคลุมหลายบริการ

ขั้นตอนเพิ่มเติมที่คุณควรทำเพื่อปกป้องบัญชีของผู้ใช้คือการใช้การปกป้องข้ามบัญชีโดยใช้บริการการปกป้องข้ามบัญชีของ Google บริการนี้ช่วยให้คุณสมัครรับการแจ้งเตือนเหตุการณ์ด้านความปลอดภัยซึ่งจะส่งข้อมูลเกี่ยวกับการเปลี่ยนแปลงที่สำคัญในบัญชีผู้ใช้ไปยังแอปพลิเคชัน จากนั้น คุณสามารถใช้ข้อมูลดังกล่าวเพื่อดําเนินการโดยขึ้นอยู่กับวิธีตอบสนองต่อเหตุการณ์

ตัวอย่างประเภทเหตุการณ์ที่บริการการปกป้องบัญชีข้ามของ Google ส่งไปยังแอปของคุณมีดังนี้

  • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
  • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
  • https://schemas.openid.net/secevent/risc/event-type/account-disabled

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้การป้องกันแบบครอบคลุมหลายบริการและรายการเหตุการณ์ทั้งหมดที่ใช้ได้ได้จากหน้า ปกป้องบัญชีผู้ใช้ด้วยการป้องกันแบบครอบคลุมหลายบริการ