|
| 1 | +--- |
| 2 | +title: "Authentication" |
| 3 | +icon: "lucide/Shield" |
| 4 | +description: "Secure your AG2 backend with user authentication on /chat" |
| 5 | +--- |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +CopilotKit supports user authentication for AG2 backends in two deployment modes: |
| 10 | + |
| 11 | +- **LangGraph Platform equivalent**: managed runtime forwarding to your AG2 `/chat` endpoint |
| 12 | +- **Self-hosted runtime**: your own CopilotKit runtime forwarding to your AG2 `/chat` endpoint |
| 13 | + |
| 14 | +Both approaches let your AG2 backend access authenticated user context and enforce authorization. |
| 15 | + |
| 16 | +This pattern enables your backend to: |
| 17 | + |
| 18 | +- Validate user tokens before dispatching the agent |
| 19 | +- Attach authenticated user context to agent state/tools |
| 20 | +- Enforce authorization decisions server-side |
| 21 | + |
| 22 | +<Callout type="info"> |
| 23 | + CopilotKit consumes AG-UI protocol events streamed by AG2 over <code>/chat</code>. See the <a href="https://docs.ag2.ai/latest/docs/user-guide/ag-ui/" target="_blank">AG2 AG-UI integration docs</a>. |
| 24 | +</Callout> |
| 25 | + |
| 26 | +## How It Works |
| 27 | + |
| 28 | +```mermaid |
| 29 | +sequenceDiagram |
| 30 | + participant Frontend |
| 31 | + participant CopilotKit |
| 32 | + participant AG2Backend |
| 33 | + participant Agent |
| 34 | +
|
| 35 | + Frontend->>CopilotKit: authorization: "user-token" |
| 36 | + CopilotKit->>AG2Backend: Forward auth token header |
| 37 | + AG2Backend->>AG2Backend: Validate token |
| 38 | + AG2Backend->>Agent: Dispatch with authenticated context |
| 39 | + Agent->>Agent: Access authenticated user context |
| 40 | +``` |
| 41 | + |
| 42 | +## Frontend Setup |
| 43 | + |
| 44 | +Pass your authentication token via the `properties` prop: |
| 45 | + |
| 46 | +```tsx |
| 47 | +<CopilotKit |
| 48 | + runtimeUrl="/api/copilotkit" |
| 49 | + properties={{ |
| 50 | + authorization: userToken, // forwarded to AG2 /chat |
| 51 | + }} |
| 52 | +> |
| 53 | + <YourApp /> |
| 54 | +</CopilotKit> |
| 55 | +``` |
| 56 | + |
| 57 | +**Note**: The `authorization` property is forwarded to your AG2 `/chat` endpoint as a request header. |
| 58 | + |
| 59 | +## LangGraph Platform Deployment |
| 60 | + |
| 61 | +**For managed deployments**, protect your AG2 `/chat` endpoint with token-header validation. |
| 62 | + |
| 63 | +### Setup Authentication Handler |
| 64 | + |
| 65 | +```python |
| 66 | +from fastapi import FastAPI, Header, HTTPException |
| 67 | +from fastapi.responses import StreamingResponse |
| 68 | +from autogen import ConversableAgent, LLMConfig |
| 69 | +from autogen.ag_ui import AGUIStream, RunAgentInput |
| 70 | + |
| 71 | +agent = ConversableAgent( |
| 72 | + name="assistant", |
| 73 | + system_message="You are a helpful assistant.", |
| 74 | + llm_config=LLMConfig({"model": "gpt-4o-mini"}), |
| 75 | +) |
| 76 | + |
| 77 | +stream = AGUIStream(agent) |
| 78 | +app = FastAPI() |
| 79 | + |
| 80 | +def validate_your_token(token: str) -> dict: |
| 81 | + # Replace this with your own validation logic. |
| 82 | + if token != "valid-token": |
| 83 | + raise HTTPException(status_code=401, detail="Unauthorized") |
| 84 | + return {"user_id": "user_123", "role": "member"} |
| 85 | + |
| 86 | +@app.post("/chat") |
| 87 | +async def run_agent( |
| 88 | + message: RunAgentInput, |
| 89 | + accept: str | None = Header(None), |
| 90 | + authorization: str | None = Header(None), |
| 91 | +): |
| 92 | + if not authorization: |
| 93 | + raise HTTPException(status_code=401, detail="Missing authorization header") |
| 94 | + |
| 95 | + token = authorization.replace("Bearer ", "") |
| 96 | + user_info = validate_your_token(token) |
| 97 | + |
| 98 | + # Use user_info to scope tools, state, and data access before dispatch. |
| 99 | + return StreamingResponse( |
| 100 | + stream.dispatch(message, accept=accept), |
| 101 | + media_type=accept or "text/event-stream", |
| 102 | + ) |
| 103 | +``` |
| 104 | + |
| 105 | +### Access User in Agent |
| 106 | + |
| 107 | +Use validated user identity to scope tool calls and data access: |
| 108 | + |
| 109 | +```python |
| 110 | +from typing import Annotated |
| 111 | +from autogen import ContextVariables |
| 112 | + |
| 113 | +@agent.register_for_llm(description="Return account data for the authenticated user.") |
| 114 | +def get_account_data( |
| 115 | + context: ContextVariables, |
| 116 | + account_id: Annotated[str, "The target account id"], |
| 117 | +) -> dict: |
| 118 | + user = context.get("auth_user") |
| 119 | + if not user: |
| 120 | + return {"error": "unauthorized"} |
| 121 | + # Example check: ensure user can access this account |
| 122 | + if account_id not in user.get("allowed_accounts", []): |
| 123 | + return {"error": "forbidden"} |
| 124 | + return {"account_id": account_id, "owner": user["user_id"]} |
| 125 | +``` |
| 126 | + |
| 127 | +## Self-hosted Deployment |
| 128 | + |
| 129 | +**For self-hosted deployments**, use the same `/chat` header-validation pattern in your own FastAPI service. |
| 130 | + |
| 131 | +### Setup Dynamic Agent Configuration |
| 132 | + |
| 133 | +```python |
| 134 | +from fastapi import FastAPI, Header, HTTPException |
| 135 | +from fastapi.responses import StreamingResponse |
| 136 | +from autogen import ConversableAgent, LLMConfig |
| 137 | +from autogen.ag_ui import AGUIStream, RunAgentInput |
| 138 | + |
| 139 | +agent = ConversableAgent( |
| 140 | + name="assistant", |
| 141 | + system_message="You are a helpful assistant.", |
| 142 | + llm_config=LLMConfig({"model": "gpt-4o-mini"}), |
| 143 | +) |
| 144 | + |
| 145 | +stream = AGUIStream(agent) |
| 146 | +app = FastAPI() |
| 147 | + |
| 148 | +@app.post("/chat") |
| 149 | +async def run_agent( |
| 150 | + message: RunAgentInput, |
| 151 | + accept: str | None = Header(None), |
| 152 | + authorization: str | None = Header(None), |
| 153 | +): |
| 154 | + if not authorization: |
| 155 | + raise HTTPException(status_code=401, detail="Unauthorized") |
| 156 | + # Validate token here, then dispatch |
| 157 | + return StreamingResponse( |
| 158 | + stream.dispatch(message, accept=accept), |
| 159 | + media_type=accept or "text/event-stream", |
| 160 | + ) |
| 161 | +``` |
| 162 | + |
| 163 | +### Access User in Agent |
| 164 | + |
| 165 | +After token validation, persist user identity in request-scoped context and enforce access checks in AG2 tools/state reads. |
| 166 | + |
| 167 | +## Universal Authentication Pattern |
| 168 | + |
| 169 | +For backends that run in both managed and self-hosted modes, use this pattern: |
| 170 | + |
| 171 | +```python |
| 172 | +def extract_user_from_auth_header(authorization: str | None) -> dict | None: |
| 173 | + if not authorization: |
| 174 | + return None |
| 175 | + token = authorization.replace("Bearer ", "") |
| 176 | + return validate_your_token(token) |
| 177 | +``` |
| 178 | + |
| 179 | +Then: |
| 180 | + |
| 181 | +- Read `authorization` on `/chat` |
| 182 | +- Validate token before `stream.dispatch(...)` |
| 183 | +- Attach user context for tool/state authorization |
| 184 | +- Deny unauthorized or out-of-scope access |
| 185 | + |
| 186 | +## Security Notes |
| 187 | + |
| 188 | +### LangGraph Platform |
| 189 | + |
| 190 | +- **Token Validation**: Validate tokens on your AG2 `/chat` endpoint |
| 191 | +- **User Scoping**: Scope data access by authenticated user identity |
| 192 | + |
| 193 | +### Self-hosted |
| 194 | + |
| 195 | +- **Manual Validation**: Implement and maintain your own validation logic |
| 196 | +- **Header Forwarding**: Ensure your runtime forwards `authorization` to AG2 |
| 197 | + |
| 198 | +### General Best Practices |
| 199 | + |
| 200 | +- **Permission Checks**: Enforce role-based checks in AG2 tools |
| 201 | +- **Transport Security**: Serve `/chat` over HTTPS |
| 202 | +- **Least Privilege**: Return only data needed for the current user/task |
| 203 | + |
| 204 | +## Troubleshooting |
| 205 | + |
| 206 | +### Common Issues |
| 207 | + |
| 208 | +**Token not reaching backend**: |
| 209 | + |
| 210 | +- Ensure you're passing `authorization` in `properties` |
| 211 | +- Confirm your runtime forwards headers to AG2 `/chat` |
| 212 | + |
| 213 | +**Invalid token format**: |
| 214 | + |
| 215 | +- Handle both raw tokens and `Bearer <token>` formats consistently |
| 216 | + |
| 217 | +**Unexpected anonymous access**: |
| 218 | + |
| 219 | +- Verify `authorization` checks happen before calling `stream.dispatch(...)` |
| 220 | + |
| 221 | +## Next Steps |
| 222 | + |
| 223 | +- [Configure chat UI with AG2 backend ->](/ag2/agentic-chat-ui) |
| 224 | +- [Learn about shared state ->](/ag2/shared-state) |
| 225 | +- [Implement human-in-the-loop workflows ->](/ag2/human-in-the-loop) |
0 commit comments