crewAIInc/crewAI · error · ValueError

Either jwks_url or introspection_url must be provided for to

Error message

Either jwks_url or introspection_url must be provided for token validation

What it means

A pydantic ValidationError raised inside OAuth2ServerAuth's model_validator(mode='after') when the configuration provides neither jwks_url nor introspection_url. The scheme refuses to construct because it would have no way to validate tokens. It surfaces at configuration time (startup), not per request.

Source

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

    )
    jwks_cache_ttl: int = Field(
        default=3600,
        description="TTL for JWKS cache in seconds",
        ge=60,
    )
    clock_skew_seconds: float = Field(
        default=30.0,
        description="Allowed clock skew for token validation",
        ge=0.0,
    )

    _jwk_client: PyJWKClient | None = PrivateAttr(default=None)

    @model_validator(mode="after")
    def _validate_and_init(self) -> Self:
        """Validate configuration and initialize JWKS client if needed."""
        if not self.jwks_url and not self.introspection_url:
            raise ValueError(
                "Either jwks_url or introspection_url must be provided for token validation"
            )

        if self.introspection_url:
            if not self.introspection_client_id or not self.introspection_client_secret:
                raise ValueError(
                    "introspection_client_id and introspection_client_secret are required "
                    "when using token introspection"
                )

        if self.jwks_url:
            self._jwk_client = PyJWKClient(
                str(self.jwks_url), lifespan=self.jwks_cache_ttl
            )

        return self

    async def authenticate(self, token: str) -> AuthenticatedUser:

View on GitHub (pinned to 754d7323be)

Solutions

  1. Provide at least one validation endpoint: OAuth2ServerAuth(jwks_url='https://idp/.well-known/jwks.json', ...) for JWTs.
  2. For opaque tokens, provide introspection_url plus introspection_client_id and introspection_client_secret.
  3. Validate the config at startup and log which fields are missing instead of discovering it via the traceback.
  4. If both are configured, ensure at least one URL is reachable before going live.

Example fix

# before
auth = OAuth2ServerAuth(issuer="https://idp", audience="api")  # ValidationError

# after
auth = OAuth2ServerAuth(
    issuer="https://idp", audience="api",
    jwks_url="https://idp/.well-known/jwks.json",
)
Defensive patterns

Strategy: validation

Validate before calling

from crewai.a2a.auth.server_schemes import OAuth2ServerAuth

# fails fast with a clear pydantic error instead of at request time
auth = OAuth2ServerAuth(
    jwks_url="https://idp/.well-known/jwks.json",  # or introspection_url + credentials
)

Try / catch

try:
    auth = OAuth2ServerAuth(**cfg)
except ValidationError as e:
    if "jwks_url or introspection_url" in str(e):
        cfg.setdefault("jwks_url", os.environ["JWKS_URL"])  # supply the missing endpoint
        auth = OAuth2ServerAuth(**cfg)

Prevention

When it happens

Trigger: Instantiating OAuth2ServerAuth() with only issuer/audience fields and no validation endpoint: OAuth2ServerAuth(issuer='https://idp', audience='api') raises immediately; or a config dict built from env vars where both JWKS_URL and INTROSPECTION_URL are empty strings.

Common situations: Copy-pasting an OIDCAuth config into OAuth2ServerAuth and dropping jwks_url; env-var-driven configs where the variable name changed between versions; partially filled YAML config files.

Related errors


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