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

ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมการตรวจสอบสิทธิ์ในเอกสารประกอบของ Google Cloud Platform

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

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

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

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

ภาพรวม

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

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

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

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

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

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

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

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

ขั้นแรก สร้างบัญชีบริการ:

  1. เปิด Service accounts page
  2. If prompted, select a project, or create a new one.
  3. คลิก สร้างบัญชีผู้ใช้บริการ
  4. ภายใต้รายละเอียดบัญชีบริการพิมพ์ชื่อ, ID, และคำอธิบายสำหรับบัญชีผู้ใช้บริการจากนั้นคลิกสร้างและดำเนินการต่อ
  5. ตัวเลือก: ภายใต้แกรนท์นี้การเข้าถึงบัญชีผู้ใช้บริการในโครงการเลือกบทบาท IAM จะกำหนดให้กับบัญชีผู้ใช้บริการ
  6. คลิกดำเนินการต่อ
  7. ตัวเลือก: การเข้าถึงผู้ใช้ภายใต้การให้กับบัญชีผู้ใช้บริการนี้เพิ่มผู้ใช้หรือกลุ่มที่ได้รับอนุญาตในการใช้และจัดการบัญชีผู้ใช้บริการ
  8. คลิกเสร็จสิ้น
  9. คลิก สร้างคีย์แล้วคลิกสร้าง

ถัดไป สร้างรหัสบัญชีบริการ:

  1. คลิกที่อยู่อีเมลสำหรับบัญชีบริการที่คุณสร้างขึ้น
  2. คลิกที่คีย์แท็บ
  3. ในการเพิ่มคีย์รายการแบบหล่นลงที่เลือกสร้างคีย์ใหม่
  4. คลิกสร้าง

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

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

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

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

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

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

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

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

กําลังเตรียมการเรียก API ที่ได้รับอนุญาต

Java

หลังจากได้รับอีเมลของไคลเอ็นต์และคีย์ส่วนตัวจาก API Consoleแล้ว ให้ใช้ไลบรารีของไคลเอ็นต์ 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("user@example.com");

ใช้ออบเจ็กต์ GoogleCredential เพื่อเรียก Google APIs ในแอปพลิเคชันของคุณ

Python

หลังจากได้รับอีเมลของไคลเอ็นต์และคีย์ส่วนตัวจาก API Consoleแล้ว ให้ใช้ไลบรารีของไคลเอ็นต์ Google APIs สําหรับ 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

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

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

หัวข้อต่อไปนี้อธิบายวิธีดําเนินการขั้นตอนเหล่านี้

หากการตอบกลับมีโทเค็นเพื่อการเข้าถึง คุณจะใช้โทเค็นเพื่อการเข้าถึงเพื่อเรียก 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

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

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

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

การเป็นตัวแทนของ Base64url มีดังนี้

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
การสร้างชุดการอ้างสิทธิ์ 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 ชุดการอ้างสิทธิ์ JWT ควรเรียงแบบเดียวกันกับ UTF-8 และเข้ารหัสแบบ Base64url ได้อย่างปลอดภัย ด้านล่างนี้เป็นตัวอย่างการนําเสนอไฟล์การอ้างสิทธิ์ JWT ในรูปแบบ JSON

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

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

ลายเซ็นต้องมีการเข้ารหัส 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 ที่ลงชื่อแล้ว แอปพลิเคชันสามารถใช้แอปพลิเคชันเพื่อขอโทเค็นเพื่อการเข้าถึงได้ คําขอโทเค็นเพื่อการเข้าถึงนี้เป็นคําขอ POST HTTPS และตัวเนื้อหาได้รับการเข้ารหัส URL URL แสดงอยู่ด้านล่าง

https://oauth2.googleapis.com/token

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

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

ด้านล่างนี้คือไฟล์ RAW ของคําขอ HTTPS POST ที่ใช้ในคําขอโทเค็นเพื่อการเข้าถึง

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 APIs

Java

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

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

Python

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

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

HTTP/REST

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

คุณจะลองใช้ Google 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

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

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

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

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

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

แม้ว่าโดยปกติจะใช้เวลา 24-34 ชั่วโมงจึงจะมีผล แต่การให้สิทธิ์จะ มีผลกับผู้ใช้ทั้งหมดในบัญชี 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-34 ชั่วโมงจึงจะมีผล แต่การให้สิทธิ์จะ มีผลกับผู้ใช้ทั้งหมดในบัญชี Google ของคุณ

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 ถูกต้อง หากจําเป็น ให้ซิงค์เวลาของคุณกับ Google NTP

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 ปิดอยู่

ไปที่ Google API Consoleและในส่วน IAM & Admin > Service Accounts ให้เปิดใช้บัญชีบริการที่มี "Key ID" เพื่อใช้รับรอง

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

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

หาก API ที่คุณต้องการเรียกใช้มีคําจํากัดความของบริการที่เผยแพร่ในที่เก็บ Google APIs GitHub คุณเรียกใช้ 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 ให้ระบุเวลาที่แน่นอน 3,600 วินาทีเมื่อ 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