feat(auth): Implement ID Token validation in OIDCClient
This commit is contained in:
@@ -81,6 +81,7 @@ class OIDCClient:
|
||||
scope="openid email profile"
|
||||
)
|
||||
self.metadata: Dict[str, Any] = {}
|
||||
self.jwks: Optional[Dict[str, Any]] = None
|
||||
|
||||
def fetch_metadata(self) -> Dict[str, Any]:
|
||||
"""Fetch OIDC provider metadata if not already fetched."""
|
||||
@@ -88,6 +89,16 @@ class OIDCClient:
|
||||
self.metadata = requests.get(self.server_metadata_url).json()
|
||||
return self.metadata
|
||||
|
||||
def fetch_jwks(self) -> Dict[str, Any]:
|
||||
"""Fetch OIDC provider JWKS if not already fetched."""
|
||||
if not self.jwks:
|
||||
metadata = self.fetch_metadata()
|
||||
jwks_uri = metadata.get("jwks_uri")
|
||||
if not jwks_uri:
|
||||
raise ValueError("jwks_uri not found in OIDC metadata")
|
||||
self.jwks = requests.get(jwks_uri).json()
|
||||
return self.jwks
|
||||
|
||||
def generate_pkce(self) -> Tuple[str, str]:
|
||||
"""Generate PKCE code_verifier and code_challenge."""
|
||||
code_verifier = generate_token(48)
|
||||
@@ -127,6 +138,30 @@ class OIDCClient:
|
||||
"code_verifier": code_verifier
|
||||
}
|
||||
|
||||
def validate_id_token(self, token: str, nonce: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Validate the ID Token and return its claims.
|
||||
Verifies signature (using JWKS), issuer, audience, and nonce.
|
||||
"""
|
||||
metadata = self.fetch_metadata()
|
||||
jwks = self.fetch_jwks()
|
||||
|
||||
try:
|
||||
claims = jwt.decode(
|
||||
token,
|
||||
jwks,
|
||||
algorithms=metadata.get("id_token_signing_alg_values_supported", ["RS256"]),
|
||||
audience=self.client_id,
|
||||
issuer=metadata.get("issuer")
|
||||
)
|
||||
|
||||
if nonce and claims.get("nonce") != nonce:
|
||||
raise ValueError("Invalid nonce")
|
||||
|
||||
return claims
|
||||
except JWTError as e:
|
||||
raise ValueError(f"ID Token validation failed: {str(e)}")
|
||||
|
||||
def get_login_url(self) -> str:
|
||||
"""Legacy method for generating simple authorization URL."""
|
||||
metadata = self.fetch_metadata()
|
||||
|
||||
Reference in New Issue
Block a user