33
44from __future__ import annotations
55
6- import base64
7- import json
8- import os
96import logging
7+ import os
108
119from ag_ui .core import RunAgentInput , RunErrorEvent
1210from bedrock_agentcore .identity .auth import requires_access_token
1715from langchain_mcp_adapters .client import MultiServerMCPClient
1816from langgraph_checkpoint_aws import AgentCoreMemorySaver
1917
18+ from utils .auth import extract_user_id_from_context
2019from utils .ssm import get_ssm_parameter
2120from tools import query_data , AgentState , todo_tools
2221
3130When asked about your tools, list them and explain what they do."""
3231
3332
34- def decode_jwt_sub (authorization_header : str | None ) -> str | None :
35- if not authorization_header :
36- return None
37-
38- parts = authorization_header .strip ().split ()
39- if len (parts ) != 2 or parts [0 ].lower () != "bearer" :
40- return None
41-
42- token_parts = parts [1 ].split ("." )
43- if len (token_parts ) < 2 :
44- return None
45-
46- try :
47- payload = token_parts [1 ]
48- payload += "=" * ((4 - len (payload ) % 4 ) % 4 )
49- decoded = base64 .urlsafe_b64decode (payload .encode ("utf-8" ))
50- sub = json .loads (decoded ).get ("sub" )
51- return sub if isinstance (sub , str ) and sub else None
52- except Exception :
53- return None
54-
55-
56- def resolve_actor_id (
57- input_data : RunAgentInput , authorization_header : str | None
58- ) -> str | None :
59- forwarded_props = (
60- input_data .forwarded_props
61- if isinstance (input_data .forwarded_props , dict )
62- else {}
63- )
64-
65- for key in ACTOR_ID_KEYS :
66- value = forwarded_props .get (key )
67- if isinstance (value , str ) and value :
68- return value
69-
70- return decode_jwt_sub (authorization_header )
71-
72-
7333@requires_access_token (
7434 provider_name = os .environ ["GATEWAY_CREDENTIAL_PROVIDER_NAME" ],
7535 auth_flow = "M2M" ,
@@ -123,14 +83,26 @@ def _build_checkpointer() -> AgentCoreMemorySaver:
12383 region_name = os .environ .get ("AWS_DEFAULT_REGION" , "us-east-1" ),
12484 )
12585
86+
12687@app .entrypoint
12788async def invocations (payload : dict , context : RequestContext ):
12889 input_data = RunAgentInput .model_validate (payload )
129- authorization_header = None
130- if context .request_headers :
131- authorization_header = context .request_headers .get ("Authorization" )
13290
133- actor_id = resolve_actor_id (input_data , authorization_header )
91+ # Extract actor identity securely from the validated JWT token.
92+ try :
93+ actor_id = extract_user_id_from_context (context )
94+ except ValueError :
95+ # Fall back to forwarded props if JWT extraction fails (e.g. local dev).
96+ forwarded = (
97+ input_data .forwarded_props
98+ if isinstance (input_data .forwarded_props , dict )
99+ else {}
100+ )
101+ actor_id = next (
102+ (forwarded [k ] for k in ACTOR_ID_KEYS if k in forwarded and forwarded [k ]),
103+ None ,
104+ )
105+
134106 if not actor_id :
135107 raise ValueError (
136108 "Missing actor identity. Provide forwardedProps.actor_id/user_id "
@@ -151,16 +123,16 @@ async def invocations(payload: dict, context: RequestContext):
151123 checkpointer = _build_checkpointer (),
152124 middleware = [CopilotKitMiddleware ()],
153125 system_prompt = SYSTEM_PROMPT ,
154- state_schema = AgentState , # extends BaseAgentState with todos: list[Todo]
126+ state_schema = AgentState ,
155127 )
156128
157- request_agent = LangGraphAGUIAgent (
129+ agent = LangGraphAGUIAgent (
158130 name = "LangGraphSingleAgent" ,
159131 description = "LangGraph single agent exposed via AG-UI" ,
160132 graph = graph ,
161133 config = {"configurable" : {"actor_id" : actor_id }},
162134 )
163- async for event in request_agent .run (input_data ):
135+ async for event in agent .run (input_data ):
164136 if event is not None :
165137 yield event .model_dump (mode = "json" , by_alias = True , exclude_none = True )
166138 except Exception as exc :
@@ -172,4 +144,4 @@ async def invocations(payload: dict, context: RequestContext):
172144
173145
174146if __name__ == "__main__" :
175- app .run ()
147+ app .run ()
0 commit comments