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

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

ระบบ Google OAuth 2.0 รองรับการโต้ตอบแบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ เช่น การโต้ตอบระหว่างเว็บแอปพลิเคชันกับบริการของ Google ในสถานการณ์นี้ คุณต้องมีบัญชีบริการซึ่งเป็นบัญชีของแอปพลิเคชันของคุณแทนที่จะเป็นผู้ใช้ปลายทาง แอปพลิเคชันของคุณเรียกใช้ Google API ในนามของบัญชีบริการ ดังนั้นผู้ใช้จึงไม่ได้มีส่วนเกี่ยวข้องโดยตรง บางครั้งสถานการณ์นี้จะเรียกว่า "OAuth สองทาง," หรือ "2LO." (คําศัพท์ที่เกี่ยวข้อง & OAuth-3-legte OAuth" หมายถึงสถานการณ์ที่แอปพลิเคชันของคุณเรียก 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 คุณต้องดึงข้อมูลเข้าสู่ระบบเหล่านี้ใน วิธีสร้างข้อมูลรับรองของบัญชีบริการหรือดูข้อมูลเข้าสู่ระบบสาธารณะที่สร้างไว้แล้วมีดังนี้

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

  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 ในนามของผู้ใช้ การให้สิทธิ์บัญชีบริการเพื่อเข้าถึงข้อมูลแทนผู้ใช้ในโดเมน จะเรียกว่า "การมอบสิทธิ์ทั่วทั้งโดเมน&quot ให้แก่บัญชีบริการ

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

  1. จากคอนโซลผู้ดูแลระบบของโดเมน Google Workspace ให้ไปที่เมนูหลัก > ความปลอดภัย > การควบคุมการเข้าถึงข้อมูลและ gt; การควบคุม 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 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 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 (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 ชุดการอ้างสิทธิ์ 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 ที่มีการเข้ารหัสแบบ UTF-8 และมีการเข้ารหัสแบบ Safe64url เช่นเดียวกับส่วนหัว 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) ด้วยคีย์ส่วนตัวที่ได้รับจาก 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 รวมถึงลายเซ็น

ด้านล่างนี้คือไฟล์ 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 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 ที่ได้รับอนุญาต เช่น หากต้องการเรียกใช้ Cloud Administration API เวอร์ชัน 1 รุ่นเบต้า 3 ให้ทําดังนี้
    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

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

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

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

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

ไปที่ Google API Consoleจากนั้นไปที่ IAM & Admin > Service Accounts เพื่อเปิดใช้บัญชีบริการซึ่งมี "Key ID" ที่ใช้รับรองการยืนยัน

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

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

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