若要為 GitHub App 產生 JWT,請建構一個嚴格的 JSON 聲明 (claims) 物件,其中包含 App 的識別碼與短效期的時間戳記,使用至少 32 位元組的 UTF-8 共用密鑰,以 HMAC-SHA-256 簽署編碼後的標頭與酬載,並以句點串接三段 base64url 字串。本頁的 JWT 產生器 完全在您的瀏覽器中產生該精簡的 HS256 字串,受保護的標頭固定為 {"alg":"HS256","typ":"JWT"},且每個段落皆使用無填充的 RFC 4648 base64url 編碼。其結果是一個有效的開發權杖,適合用於測試 GitHub App 認證流程中的 JWT 建立步驟,以及驗證您 JOSE 函式庫的行為。然而,它並不能取代 GitHub API 在正式環境中對 GitHub App 所要求的 RS256 私密金鑰簽章 —— 那個簽署步驟應交由維護良好的 JOSE 函式庫以及您註冊的 PEM 私密金鑰來執行。請使用本頁學習並驗證 JWT 結構,再以您平台所支援的函式庫簽署真正的 GitHub App 權杖。

已簽署 JWT 在 GitHub App 認證中的角色
GitHub App 透過兩步驟交換向 GitHub API 進行認證。首先,App 將一個短效期的 JWT 傳送到 /app 認證端點;GitHub 會驗證簽章、根據已註冊的 App ID 檢查發行者 (issuer) 聲明,並確認權杖尚未過期。若一切相符,GitHub 會回傳一個與特定儲存庫或組織安裝綁定的安裝存取權杖。該安裝權杖才是您的指令碼與 CI 工作用於日常 API 呼叫的憑證。
JWT 本身僅承載少數幾個聲明。發行者 (iss) 為您的 GitHub App 數值 ID。簽發時間 (iat) 時間戳記為 JWT 建立的當下,以 Unix 秒數表示。到期時間 (exp) 設上限了權杖的存活期 —— GitHub 目前將 App 的權杖上限設為十分鐘,並拒絕任何更長的權杖。GitHub 也接受選擇性的生效起始時間 (nbf) 時間戳記,並會拒絕那個時間點過度未來的權杖。其他資訊 —— 例如安裝 ID、儲存庫名稱、使用者範圍 —— 不應放在 JWT 本身,而是隨安裝權杖一併提供。
這就是為什麼即使該權杖從未用於例行請求,JWT 格式仍然重要。一個格式錯誤的 JSON 聲明物件、錯誤的演算法或過期的時間戳記,都會導致 GitHub 拒絕整個認證,而您的整合在 JWT 正確產生之前都會收到 401 回應。在本機端建立一個 JWT,能讓您區分失敗究竟是出在建構程式碼還是網路呼叫。
HS256 對 RS256:哪個演算法適合哪個步驟
GitHub 的 API 預期 GitHub App 的 JWT 使用 RS256 簽署,這是一種非對稱演算法,在 App 端使用 RSA 私密金鑰,在 GitHub 端則使用它已為該 App 儲存的公開金鑰。HS256 是對稱演算法,使用同一把共用密鑰進行簽署與驗證,因此單獨使用它無法對 github.com 進行認證。本頁的 JWT 產生器會輸出 HS256 權杖,並明確將受保護標頭固定為 {"alg":"HS256","typ":"JWT"}。這使得本頁對結構性步驟 —— 建立聲明、編碼段落、驗證產生的字串 —— 很實用,但它不會產生 GitHub API 對真正的 GitHub App 所接受的權杖。
| 屬性 | HS256(本頁) | RS256(正式環境的 GitHub App) |
|---|---|---|
| 金鑰類型 | 共用對稱密鑰,UTF-8 至少 32 位元組 | RSA 私密金鑰 (PEM),至少 2048 位元 |
| 驗證金鑰 | 兩端使用相同的密鑰 | 已向 GitHub 註冊的公開金 |
| JWA 參考 | RFC 7518 HMAC with SHA-256 | RFC 7518 RSASSA-PKCS1-v1_5 with SHA-256 |
| github.com 是否接受 | 否 | 是 |
| 在本頁的使用方式 | 學習 JWT 結構與測試驗證器 | 正式環境的 GitHub App 認證 |
固定演算法對安全性很重要。允許使用者輸入來選擇演算法,正是 "alg":"none" 或演算法混淆攻擊被引入的途徑。透過固定為 HS256,本頁可避免隨意貼上時意外產生未簽署或看似非對稱的權杖。
使用 JWT 產生器在本機端產生 GitHub App JWT
- 開啟 JWT 產生器,並將一個嚴格的 JSON 聲明物件貼到 claims 欄位。該物件必須是語法上有效的 JSON;陣列、null、註解、尾端逗號、undefined、NaN、Infinity 以及 JavaScript 運算式都會被拒絕。一個最小的 GitHub App 風格聲明物件看起來像 {"iss":"123456","iat":1719436800,"exp":1719437400} —— 請將其中的數值 App ID 與目前 Unix 秒數的時間戳記替換為您自己的值。
- 在 secret 欄位輸入密鑰,或點擊隨機按鈕來產生一組。隨機按鈕會產生 32 位元組的加密強度隨機位元組,並以 64 個十六進位字元顯示;這些字元會作為 UTF-8 的 HMAC 密使用。密鑰必須包含至少 32 個 UTF-8 位元組;對於非 ASCII 文字而言,字元數與位元組數可能不同。對 GitHub App 流程而言,這僅作為開發用途的佔位符 —— 正式環境的密鑰是您的 PEM 私密金。
- 點擊 generate 按鈕。該工具會編譯固定的標頭 {"alg":"HS256","typ":"JWT"},編碼您的聲明物件,使用 HMAC-SHA-256 簽署「編碼後的標頭 + 句點 + 編碼後的酬載」,並輸出以句點分隔的三個精簡段落。
- 檢視這三個段落。第一段是 base64url 編碼後的標頭,對固定的 HS256/JWT 標頭而言,長度永遠是 36 個字元。第二段是 base64url 編碼後的聲明物件,長度取決於您的輸入。第三段是 base64url 編碼後的 32 位元組簽章,會編碼為 43 個無填充的字元。
- 複製產生的權杖。複製動作會將該精簡字串放入您的剪貼簿。請將剪貼簿內容視為持有者憑證 (bearer credentials) —— 它們可能被剪貼簿歷史、螢幕擷取畫面、瀏器擴充功能、日誌或聊天工具所留存。
- 在將權杖視為符合正式環境的輸出之前,請使用維護良好的 JOSE 函式庫進行驗證。驗證呼叫必須明確指定演算法、預期的發行者,以及您應用程式強制執行的任何對象或生命週期原則。只有經過驗證的權杖才可信賴。
三段精簡 JWT 段落的剖析
無論使用何種演算法,每個 JWT 都是三個以句點分隔的 base64url 字串。該結構定義於 RFC 7519,簽署規則則定義於 RFC 7515。就本頁固定的 HS256 標頭而言,這些段落永遠遵循相同的形狀:
| 段落 | 內容 | 編碼方式 | 在 HS256 此處的長度 |
|---|---|---|---|
| 標頭 (Header) | {"alg":"HS256","typ":"JWT"} | 先 UTF-8 再 RFC 4648 base64url,無填充 | 36 個字元 |
| 酬載 (Payload) | 您嚴格的 JSON 聲明物件 | 先 UTF-8 再 RFC 4648 base64url,無填充 | 取決於聲明數量與長度 |
| 簽章 (Signature) | 使用 32+ 位元組 UTF-8 密對 header.payload 進行 HMAC-SHA-256 | 對原始 32 位元組 MAC 進行 RFC 4648 base64url,無填充 | 43 個字元 |
簽署輸入正好就是位元組序列 <encoded-header>.<encoded-payload> —— 兩段之間僅有一個句點,沒有前後空白字元,也沒有尾端換行。Web Crypto 將密鑰匯入為使用 SHA-256 的原始 HMAC 金鑰,並對該確切的位元組序列進行簽署。標頭、酬載或句點位置的任何字元變更,都會在驗證時改變第三段,而這正是 JWT 設計上所提供的完整性保護。
若您想檢視剛剛產生的內容,請將該權杖貼到 JWT 解碼器,即可在本機端對標頭與酬載進行 base64url 解碼。解碼後可看到您實際輸出的聲明 —— 這有助於在將權杖送交驗證器之前,先抓到 iss 中的拼字錯誤或 iat 中顛倒的數字。
使用維護良好的 JOSE 函式庫驗證複製的權杖
語法上有效的 HS256 權杖未必是安全或可被接受的權杖。驗證這一步會根據您應用程式的信任原則,確認簽章、發行者、對象與生命週期。產生器並不會執行這一步 —— 它僅輸出精簡字串。
一個最基本的驗證呼叫會使用明確的演算法允許清單、預期的發行者聲明、共用密,以及對 iat、nbf 與 exp 時鐘飄移的容忍度。NumericDate 的數值是自 Unix 紀元起算的秒數,而非 JavaScript 的毫秒數;若您的驗證器使用了毫秒時間戳記,該 JWT 將看起來像已過期數十年。即使簽章通過驗證,也應允許驗證器拒絕未知的標頭參數與未預期的演算法 —— 這道防線正是防止來自其他系統的權杖被呈交給您的服務時,出現演算法混淆攻擊的關鍵。若您想要無需撰寫程式碼的逐步解說,了解驗證器正在讀取什麼,可參閱如何在瀏覽器中解碼 JWT 存取權杖指南,從驗證端展示相同的段落。
特別針對 GitHub App 的情境,請勿將此處產生的 HS256 權杖傳送給 GitHub API —— 它會因為演算法與 GitHub 為您 App 所儲存的不同而被拒絕。請使用本頁驗證 JWT 建構流程,然後在您實際呼叫 GitHub 時,切換至您函式庫的 RS256 模式並使用您註冊的 PEM 私密金鑰。
貼上密鑰或聲明前的安全考量
HS256 會簽署精簡資料,但不會將其加密。任何收到該權杖的人,都能無需密鑰地對標頭與酬載進行 base64url 解碼。切勿僅因 JWT 已被簽署,就將密碼、私密金鑰、個人紀錄或機密的應用程式資料放入 JWT 中。簽章僅在驗證者使用正確密鑰並驗證結果時,才能偵測出修改。
產生的隨機密是由 32 個加密強度隨機位元組衍生而來的 64 個十六進位字元,但它們會顯示於瀏覽器中,並可能被螢幕取畫面、瀏覽器擴充功能或剪貼簿工具所擷取。請將其視為可見的開發材料,而非自動佈建的正式環境密鑰。若真實的密鑰或作用中的權杖被貼到其預定範圍之外的任何環境中,請將其輪替或撤銷,而不要假設本機實作能讓揭露行為變得無害。
聲明輸入必須是嚴格的 JSON 物件 —— 這是強制執行而非僅供建議的規則。註解、尾端逗號與 JavaScript 運算式皆不允許,因為它們會讓隨意貼上的字串偏離驗證器所預期的內容。如有疑慮,請在貼到產生器之前,先使用 JSON 驗證器驗證聲明物件,這樣錯誤位置會被精確標示在某一行與某一欄。
若您正在權衡各種選項,如何在 Angular 應用程式中解碼 JWT 權杖對此有詳細說明。