{"record":{"id":"f470fc5190a14582","repo":"crewAIInc/crewAI","slug":"authorization-callback-not-set","errorCode":null,"errorMessage":"Authorization callback not set","messagePattern":"Authorization callback not set","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai/src/crewai/a2a/auth/client_schemes.py","lineNumber":500,"sourceCode":"\n        Args:\n            client: HTTP client for making token request.\n\n        Raises:\n            ValueError: If authorization callback is not set.\n            httpx.HTTPStatusError: If token request fails.\n        \"\"\"\n        params = {\n            \"response_type\": \"code\",\n            \"client_id\": self.client_id,\n            \"redirect_uri\": self.redirect_uri,\n            \"scope\": \" \".join(self.scopes),\n        }\n        auth_url = f\"{self.authorization_url}?{urllib.parse.urlencode(params)}\"\n\n        if self._authorization_callback is None:\n            msg = \"Authorization callback not set\"\n            raise ValueError(msg)\n        auth_code = await self._authorization_callback(auth_url)\n\n        data = {\n            \"grant_type\": \"authorization_code\",\n            \"code\": auth_code,\n            \"client_id\": self.client_id,\n            \"client_secret\": self.client_secret,\n            \"redirect_uri\": self.redirect_uri,\n        }\n\n        response = await client.post(self.token_url, data=data)\n        response.raise_for_status()\n\n        token_data = response.json()\n        self._access_token = token_data[\"access_token\"]\n        self._refresh_token = token_data.get(\"refresh_token\")\n\n        expires_in = token_data.get(\"expires_in\", 3600)","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai/src/crewai/a2a/auth/client_schemes.py#L482-L518","documentation":"In the OAuth2 authorization-code flow of crewai's A2A client, _fetch_initial_token builds the consent URL and must hand it to the user via the registered callback to obtain an authorization code. If set_authorization_callback() was never called, the token exchange cannot even start and raises ValueError('Authorization callback not set').","triggerScenarios":"Triggering the initial token fetch (no cached access token) on an OAuth2ClientScheme whose _authorization_callback is None - typically the first authentication attempt after object creation without setup.","commonSituations":"Automated/headless A2A clients where nobody wired a consent callback; refactors that construct the scheme in a different place than where the callback was registered; assuming client_credentials behavior from an authorization_code scheme.","solutions":["Call scheme.set_authorization_callback(callback) before the first authenticated request.","For headless flows, implement a callback that logs the URL and reads the code from a queue/file.","If interactive consent is not possible, switch to a client-credentials or API-key scheme instead of authorization_code."],"exampleFix":"# before\nresponse = await client.fetch_token(...)  # _authorization_callback None -> ValueError\n\n# after\nasync def get_code(url: str) -> str:\n    print('Visit:', url)\n    return input('Code: ')\n\nscheme.set_authorization_callback(get_code)\nresponse = await client.fetch_token(...)","handlingStrategy":"validation","validationCode":"scheme = OAuth2ClientScheme(...)\nif getattr(scheme, '_authorization_callback', None) is None:\n    raise SystemExit('OAuth2 code flow needs set_authorization_callback() before first token fetch')","typeGuard":"def has_auth_callback(scheme) -> bool:\n    return getattr(scheme, '_authorization_callback', None) is not None","tryCatchPattern":"try:\n    await scheme._fetch_initial_token(client)\nexcept ValueError as e:\n    if 'Authorization callback not set' in str(e):\n        scheme.set_authorization_callback(consent)\n        await scheme._fetch_initial_token(client)\n    else:\n        raise","preventionTips":["Wire the consent callback at construction time, not lazily at request time.","For headless services, prefer a scheme that does not need user consent (client credentials/API key).","Test the OAuth2 happy path in CI with a stub callback to catch setup-order bugs."],"tags":["oauth2","authentication","a2a","authorization-code"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}