{"record":{"id":"f92e67397a2e1b02","repo":"crewAIInc/crewAI","slug":"introspection-client-id-and-introspection-client-s","errorCode":null,"errorMessage":"introspection_client_id and introspection_client_secret are required when using token introspection","messagePattern":"introspection_client_id and introspection_client_secret are required when using token introspection","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai/src/crewai/a2a/auth/server_schemes.py","lineNumber":457,"sourceCode":"    clock_skew_seconds: float = Field(\n        default=30.0,\n        description=\"Allowed clock skew for token validation\",\n        ge=0.0,\n    )\n\n    _jwk_client: PyJWKClient | None = PrivateAttr(default=None)\n\n    @model_validator(mode=\"after\")\n    def _validate_and_init(self) -> Self:\n        \"\"\"Validate configuration and initialize JWKS client if needed.\"\"\"\n        if not self.jwks_url and not self.introspection_url:\n            raise ValueError(\n                \"Either jwks_url or introspection_url must be provided for token validation\"\n            )\n\n        if self.introspection_url:\n            if not self.introspection_client_id or not self.introspection_client_secret:\n                raise ValueError(\n                    \"introspection_client_id and introspection_client_secret are required \"\n                    \"when using token introspection\"\n                )\n\n        if self.jwks_url:\n            self._jwk_client = PyJWKClient(\n                str(self.jwks_url), lifespan=self.jwks_cache_ttl\n            )\n\n        return self\n\n    async def authenticate(self, token: str) -> AuthenticatedUser:\n        \"\"\"Authenticate using OAuth2 token validation.\n\n        Uses JWKS validation if jwks_url is configured, otherwise falls back\n        to token introspection.\n\n        Args:","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai/src/crewai/a2a/auth/server_schemes.py#L439-L475","documentation":"A pydantic ValidationError raised by OAuth2ServerAuth's model validator when introspection_url is set but either introspection_client_id or introspection_client_secret is missing. RFC 7662 introspection requires basic auth credentials, so the scheme refuses to construct without them. It fails at configuration time.","triggerScenarios":"OAuth2ServerAuth(introspection_url='https://idp/introspect') without client credentials; secret provided but client_id omitted; credentials left as empty strings from unset env vars.","commonSituations":"Teams wiring introspection for the first time and forgetting the IdP requires a confidential client; env vars named inconsistently (INTROSPECT_CLIENT_ID vs INTROSPECTION_CLIENT_ID); secrets stored in a vault but not injected before config load.","solutions":["Register a confidential client with your IdP and pass both values: introspection_client_id='svc' and introspection_client_secret='...'.","If the secret comes from an env var or vault, assert it is non-empty before constructing the scheme.","Note the secret accepts a plain string (coerced to SecretStr via BeforeValidator) or a SecretStr instance.","Consider jwks_url-only validation if you cannot provision an introspection client."],"exampleFix":"# before\nauth = OAuth2ServerAuth(introspection_url=\"https://idp/introspect\")  # ValidationError\n\n# after\nauth = OAuth2ServerAuth(\n    introspection_url=\"https://idp/introspect\",\n    introspection_client_id=\"my-service\",\n    introspection_client_secret=os.environ[\"INTROSPECTION_SECRET\"],\n)","handlingStrategy":"validation","validationCode":"import os\nfrom crewai.a2a.auth.server_schemes import OAuth2ServerAuth\n\nclient_id = os.environ[\"INTROSPECTION_CLIENT_ID\"]\nclient_secret = os.environ[\"INTROSPECTION_CLIENT_SECRET\"]\nassert client_id and client_secret, \"introspection requires both client id and secret\"\n\nauth = OAuth2ServerAuth(\n    introspection_url=\"https://idp/oauth/introspect\",\n    introspection_client_id=client_id,\n    introspection_client_secret=client_secret,\n)","typeGuard":null,"tryCatchPattern":"try:\n    auth = OAuth2ServerAuth(**cfg)\nexcept ValidationError as e:\n    if \"introspection_client_id and introspection_client_secret\" in str(e):\n        raise RuntimeError(\"register a confidential client with the IdP for introspection\") from e","preventionTips":["Register a confidential OAuth2 client at the IdP before enabling introspection.","Inject introspection credentials from a secret store, never hardcode them.","Assert env-provided credentials are non-empty before constructing the scheme."],"tags":["a2a","oauth2","introspection","configuration","pydantic"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}