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

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

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

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

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

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

ภาพรวม

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

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

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

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

ข้อมูลเข้าสู่ระบบของบัญชีบริการจะรวมอีเมลที่สร้างขึ้นที่ไม่ซ้ํากันและคู่คีย์สาธารณะ/ส่วนตัวอย่างน้อย 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. คลิก เสร็จสิ้น

จากนั้น สร้างรหัสบัญชีบริการ:

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

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

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

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

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

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

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

  1. จาก คอนโซลผู้ดูแลระบบของโดเมน Google Workspace ให้ไปที่เมนูหลัก > ความปลอดภัย > การเข้าถึงและการควบคุมข้อมูล > การควบคุม API
  2. ในแผงการมอบสิทธิ์ทั่วทั้งโดเมน ให้เลือกจัดการการมอบสิทธิ์ทั่วทั้งโดเมน
  3. คลิกเพิ่มใหม่
  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 API สําหรับ 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 API ในแอปพลิเคชัน

Python

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

HTTP/REST

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

  1. สร้าง JSON Web Token (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 ช่องที่ระบุอัลกอริทึมการรับรองและรูปแบบการยืนยัน ทั้ง 2 ช่องเป็นช่องที่บังคับและแต่ละช่องจะมีค่าเพียงค่าเดียว เมื่อมีการแนะนําอัลกอริทึมและรูปแบบเพิ่มเติม ส่วนหัวนี้จะเปลี่ยนแปลงตามความเหมาะสม

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

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

การนําเสนอ Base64url มีดังต่อไปนี้

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

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

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

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

https://oauth2.googleapis.com/token

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

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

ด้านล่างคือไฟล์ดิบของคําขอ 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 API

Java

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

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

Python

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

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

แม้ว่าโดยปกติจะใช้เวลา 2-3 นาที แต่อาจใช้เวลาถึง 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

แม้ว่าโดยปกติจะใช้เวลา 2-3 นาที แต่อาจใช้เวลาถึง 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 ถูกต้อง หากจําเป็น ให้ซิงค์เวลากับ 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 และผู้ดูแลระบบ > บัญชีบริการ ให้เปิดใช้บัญชีบริการที่มี "รหัสคีย์" ที่ใช้เพื่อรับรองการยืนยัน

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

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

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

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

หาก API ที่คุณต้องการเรียกมีคําจํากัดความของบริการที่เผยแพร่ในที่เก็บ Git API ของ 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 ให้ระบุเวลาที่แน่นอน 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 ที่มีการรับรองเป็นโทเค็นของ Bear:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com