This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 23b4093  Use JWKS validation for GitHub OIDC JWTs
23b4093 is described below

commit 23b4093cb66fcd26a28ffc8b69d1d2700abdc98c
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Aug 14 20:03:16 2025 +0100

    Use JWKS validation for GitHub OIDC JWTs
---
 atr/blueprints/api/api.py | 10 ++++++----
 atr/jwtoken.py            | 27 +++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 2bec872..c4dcd87 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -18,7 +18,6 @@
 
 import base64
 import hashlib
-import json
 import pathlib
 from typing import Any
 
@@ -360,9 +359,12 @@ async def jwt_github(data: models.api.JwtGithubArgs) -> 
DictResponse:
     The payload must include a valid GitHub OIDC JWT.
     """
     # TODO: This is a placeholder for the actual implementation
-    unverified_header_and_payload = 
jwtoken.unverified_header_and_payload(data.jwt)
-    unverified_header_and_payload_json = 
json.dumps(unverified_header_and_payload).encode("utf-8")
-    log.secret("GitHub OIDC JWT header and payload", 
unverified_header_and_payload_json)
+    payload = await jwtoken.verify_github_oidc(data.jwt)
+    del payload["actor_id"]
+    del payload["repository_id"]
+    del payload["repository_owner_id"]
+    del payload["run_id"]
+    log.info(f"GitHub OIDC JWT payload: {payload}")
 
     return models.api.JwtGithubResults(
         endpoint="/jwt/github",
diff --git a/atr/jwtoken.py b/atr/jwtoken.py
index eb2857f..934f8d3 100644
--- a/atr/jwtoken.py
+++ b/atr/jwtoken.py
@@ -22,6 +22,7 @@ import functools
 import secrets as secrets
 from typing import TYPE_CHECKING, Any, Final
 
+import aiohttp
 import asfquart.base as base
 import jwt
 import quart
@@ -76,6 +77,32 @@ def verify(token: str) -> dict[str, Any]:
     return jwt.decode(token, _SECRET_KEY, algorithms=[_ALGORITHM])
 
 
+async def verify_github_oidc(token: str) -> dict[str, Any]:
+    issuer = "token.actions.githubusercontent.com"
+    try:
+        async with aiohttp.ClientSession() as session:
+            r = await session.get(
+                f"https://{issuer}/.well-known/openid-configuration";,
+                timeout=aiohttp.ClientTimeout(total=5),
+            )
+            r.raise_for_status()
+            jwks_uri = (await r.json())["jwks_uri"]
+    except Exception:
+        jwks_uri = f"https://{issuer}/.well-known/jwks";
+
+    jwks_client = jwt.PyJWKClient(jwks_uri)
+    signing_key = jwks_client.get_signing_key_from_jwt(token)
+    payload = jwt.decode(
+        token,
+        key=signing_key.key,
+        algorithms=["RS256"],
+        audience="atr-test",
+        issuer=f"https://{issuer}";,
+        options={"require": ["exp", "iat"]},
+    )
+    return payload
+
+
 def _extract_bearer_token(request: quart.Request) -> str:
     header = request.headers.get("Authorization", "")
     scheme, _, token = header.partition(" ")


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to