@@ -276,7 +276,7 @@ async def call_obp_api(
276276 method = endpoint .method # HttpMethod enum value
277277 request_headers = headers or {}
278278
279- auth_method = os .getenv ("OBP_AUTHORIZATION_VIA" , "none " ).lower ()
279+ auth_method = os .getenv ("OBP_AUTHORIZATION_VIA" , "" ).lower ()
280280 match auth_method :
281281 case "oauth" :
282282 logger .info ("Using OAuth authorization method for OBP API call" )
@@ -308,13 +308,26 @@ async def call_obp_api(
308308 if body_role not in required_roles :
309309 required_roles .append (body_role )
310310
311- # If the endpoint requires no roles at all, treat it as public and skip
312- # the consent prompt. OBP will reject the call if it actually needs auth,
313- # which is a better UX than a meaningless "grant consent" dialog for e.g.
314- # GET /root.
315- if not required_roles :
311+ # Detect endpoints that need consent even without explicit role
312+ # requirements:
313+ # * account/view-scoped: path contains ACCOUNT_ID or VIEW_ID — gated by
314+ # account-access-to-a-view in OBP.
315+ # * user-scoped: path contains the `/my/` segment — identity-bound, the
316+ # response depends on which user is calling so we still need a
317+ # Consent-JWT for the user.
318+ path_segments = (endpoint .path or "" ).split ("/" )
319+ requires_view_access = "ACCOUNT_ID" in path_segments or "VIEW_ID" in path_segments
320+ is_user_scoped = "my" in path_segments
321+ account_id = (path_params or {}).get ("ACCOUNT_ID" ) or (path_params or {}).get ("account_id" )
322+ view_id = (path_params or {}).get ("VIEW_ID" ) or (path_params or {}).get ("view_id" )
323+
324+ # Endpoints with no role requirements AND no account/view/user scoping are
325+ # treated as public — skip the consent prompt (e.g. GET /root). OBP will
326+ # reject the call if it actually needs auth, which is a better UX than a
327+ # meaningless "grant consent" dialog.
328+ if not required_roles and not requires_view_access and not is_user_scoped :
316329 logger .info (
317- f"Skipping consent for { endpoint .operation_id } : endpoint has no required roles"
330+ f"Skipping consent for { endpoint .operation_id } : no required roles, not account/view-scoped, not user-scoped "
318331 )
319332 else :
320333 return json .dumps ({
@@ -325,6 +338,10 @@ async def call_obp_api(
325338 "path" : endpoint .path ,
326339 "required_roles" : required_roles ,
327340 "bank_id" : bank_id ,
341+ "account_id" : account_id ,
342+ "view_id" : view_id ,
343+ "requires_view_access" : requires_view_access ,
344+ "is_user_scoped" : is_user_scoped ,
328345 "message" : f"User consent is required to call { endpoint .operation_id } . "
329346 f"Please approve and provide a Consent-JWT." ,
330347 }, indent = 2 )
@@ -337,14 +354,14 @@ async def call_obp_api(
337354 else :
338355 logger .warning ("OBP_OPEY_CONSUMER_KEY is not set in environment variables. Consent-based authorization will fail without it." )
339356
340- case "none" :
341- # No authorization
342- logger .info ("No authorization method used for OBP API call" )
343- pass
344357 case _:
345- logger .error (f"Invalid OBP_AUTHORIZATION_VIA value: { auth_method } " )
358+ logger .error (
359+ f"Invalid OBP_AUTHORIZATION_VIA value: { auth_method !r} . "
360+ "Must be 'oauth' or 'consent'."
361+ )
346362 return json .dumps ({
347- "error" : f"Internal server error."
363+ "error" : "OBP-API calls are disabled: OBP_AUTHORIZATION_VIA "
364+ "must be set to 'oauth' or 'consent'."
348365 }, indent = 2 )
349366
350367 # Make the request
0 commit comments