{"record":{"id":"7acba1844997a1d8","repo":"crewAIInc/crewAI","slug":"oauth2-jwks-not-initialized","errorCode":null,"errorMessage":"OAuth2 JWKS not initialized","messagePattern":"OAuth2 JWKS not initialized","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"critical","filePath":"lib/crewai/src/crewai/a2a/auth/server_schemes.py","lineNumber":491,"sourceCode":"        to token introspection.\n\n        Args:\n            token: The OAuth2 access token to authenticate.\n\n        Returns:\n            AuthenticatedUser on successful authentication.\n\n        Raises:\n            HTTPException: If authentication fails.\n        \"\"\"\n        if self._jwk_client:\n            return await self._authenticate_jwt(token)\n        return await self._authenticate_introspection(token)\n\n    async def _authenticate_jwt(self, token: str) -> AuthenticatedUser:\n        \"\"\"Authenticate using JWKS JWT validation.\"\"\"\n        if self._jwk_client is None:\n            raise HTTPException(\n                status_code=HTTP_500_INTERNAL_SERVER_ERROR,\n                detail=\"OAuth2 JWKS not initialized\",\n            )\n\n        try:\n            signing_key = self._jwk_client.get_signing_key_from_jwt(token)\n\n            decode_options: Options = {\n                \"require\": self.required_claims,\n            }\n\n            claims = jwt.decode(\n                token,\n                signing_key.key,\n                algorithms=self.algorithms,\n                audience=self.audience,\n                issuer=self.issuer,\n                leeway=self.clock_skew_seconds,","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai/src/crewai/a2a/auth/server_schemes.py#L473-L509","documentation":"Raised by OAuth2ServerAuth._authenticate_jwt() when _jwk_client is None, i.e. the scheme was told to validate JWTs (introspection_url absent or authenticate() routed to _authenticate_jwt) but the JWKS client was never built. It maps to HTTP 500: an internal misconfiguration, not a client fault.","triggerScenarios":"Auth flow reaches _authenticate_jwt() with jwks_url unset — practically only possible when the object bypassed validation (model_construct) or _jwk_client was cleared, because the model validator requires at least one endpoint and builds the client when jwks_url is present.","commonSituations":"Objects built with model_construct() or copied/reconstructed in a way that skips the model validator; monkeypatched tests that null out _jwk_client; code that swaps config attributes after construction.","solutions":["Construct OAuth2ServerAuth normally with jwks_url so the validator initializes _jwk_client.","Do not use model_construct() or mutate private attrs; rebuild the scheme when config changes.","Add a startup smoke check: for a JWT-based scheme, assert scheme._jwk_client is not None.","Recreate the scheme object rather than patching fields after initialization."],"exampleFix":"# before\nauth = OAuth2ServerAuth.model_construct(issuer=\"https://idp\")  # no jwks client\n\n# after\nauth = OAuth2ServerAuth(\n    issuer=\"https://idp\", audience=\"api\",\n    jwks_url=\"https://idp/.well-known/jwks.json\",\n)","handlingStrategy":"validation","validationCode":"from crewai.a2a.auth.server_schemes import OAuth2ServerAuth\n\nauth = OAuth2ServerAuth(jwks_url=\"https://idp/.well-known/jwks.json\", ...)\nassert auth._jwk_client is not None, \"JWKS client must initialize at construction\"","typeGuard":"def is_jwt_ready(scheme) -> bool:\n    \"\"\"True when the scheme can validate JWTs (has a live JWKS client).\"\"\"\n    return getattr(scheme, \"_jwk_client\", None) is not None","tryCatchPattern":null,"preventionTips":["Construct schemes through validated paths only; avoid model_construct().","Never null out or reassign _jwk_client after construction.","Add a startup smoke authentication call to catch 500-class misconfigurations early."],"tags":["a2a","oauth2","jwks","initialization","http-500"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}