crewAIInc/crewAI · error · HTTPException

Unable to fetch signing keys

Error message

Unable to fetch signing keys

What it means

Raised by OIDCAuth.authenticate() when the PyJWKClient cannot fetch or find signing keys (PyJWKClientError), e.g. the JWKS endpoint is unreachable, returns an error, or contains no key matching the token's kid. It maps to HTTP 503 Service Unavailable, signaling a transient upstream problem rather than an invalid credential, and logs the underlying error at ERROR level with reason='jwks_client_error'.

Source

Thrown at lib/crewai/src/crewai/a2a/auth/server_schemes.py:346

        except jwt.MissingRequiredClaimError as e:
            logger.debug(
                "OIDC authentication failed",
                extra={"reason": "missing_claim", "claim": e.claim, "scheme": "oidc"},
            )
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED,
                detail=f"Missing required claim: {e.claim}",
            ) from None
        except jwt.PyJWKClientError as e:
            logger.error(
                "OIDC authentication failed",
                extra={
                    "reason": "jwks_client_error",
                    "error": str(e),
                    "scheme": "oidc",
                },
            )
            raise HTTPException(
                status_code=HTTP_503_SERVICE_UNAVAILABLE,
                detail="Unable to fetch signing keys",
            ) from None
        except jwt.InvalidTokenError as e:
            logger.debug(
                "OIDC authentication failed",
                extra={"reason": "invalid_token", "error": str(e), "scheme": "oidc"},
            )
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED,
                detail="Invalid or missing authentication credentials",
            ) from None


class OAuth2ServerAuth(ServerAuthScheme):
    """OAuth2 authentication for A2A server.

    Declares OAuth2 security scheme in AgentCard and validates tokens using

View on GitHub (pinned to 754d7323be)

Solutions

  1. Verify the JWKS URL from the server host: curl -v <jwks_url> and fix DNS/firewall/TLS issues.
  2. Retry the request after a short delay — PyJWKClient caches keys, so a transient failure clears on the next fetch.
  3. Ensure jwks_url matches the IdP's current jwks_uri from its discovery document (rotated endpoints).
  4. For containerized deployments, confirm egress rules and CA trust so the JWKS fetch succeeds.
Defensive patterns

Strategy: retry

Validate before calling

import httpx

resp = httpx.get(jwks_url, timeout=5)
assert resp.status_code == 200 and resp.json().get("keys"), (
    f"JWKS endpoint unhealthy: {resp.status_code}"
)

Try / catch

for attempt in range(3):
    try:
        return await scheme.authenticate(token)
    except HTTPException as e:
        if e.status_code == 503 and e.detail == "Unable to fetch signing keys":
            await asyncio.sleep(2 ** attempt)  # transient upstream failure: back off and retry
        else:
            raise

Prevention

When it happens

Trigger: jwks_url points to a host that is down, times out, or returns non-200; the IdP rotated keys and the cached JWKS lacks the token's kid while refetch fails; a firewall/DNS failure between the CrewAI server and the IdP; JWKS endpoint behind rate limiting returning 429.

Common situations: IdP outage or maintenance window; network egress restrictions from containers (no DNS/egress to the IdP domain); key rotation races; self-signed TLS on the JWKS endpoint breaking the fetch.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/2090db8bdab652cc. Report an issue: GitHub.