@@ -531,6 +531,50 @@ class AuthInfo(BaseModel):
531
531
api_key_info : Optional [APIKey ] = None
532
532
533
533
534
+ def is_device_public (device_id : str ) -> bool :
535
+ """
536
+ Check if a device is public (doesn't require authentication).
537
+ """
538
+ device_id_part , device_name = get_device_parts (device_id )
539
+ api_keys , owner = get_api_keys_by_device_id (device_id )
540
+
541
+ if len (api_keys ) == 0 :
542
+ # No API keys found - device doesn't exist or is not configured
543
+ return False
544
+
545
+ # Check if any API key for this device is marked as public (private_data=False)
546
+ for api_key in api_keys :
547
+ if api_key .device_id == device_id_part and api_key .device_name == device_name :
548
+ if not api_key .private_data :
549
+ return True
550
+
551
+ return False
552
+
553
+
554
+ async def flexible_auth_optional (
555
+ fief_user : Optional [FiefUserInfo ] = Depends (get_cached_fief_user_optional ()),
556
+ api_key : Optional [str ] = Header (None , alias = "X-API-Key" ),
557
+ ) -> Optional [AuthInfo ]:
558
+ """
559
+ Optional flexible authentication that accepts either Fief tokens or device API keys.
560
+ Returns None if no authentication is provided (for public device access).
561
+ """
562
+ if fief_user :
563
+ # Fief token authentication (now cached)
564
+ return AuthInfo (auth_type = "fief" , fief_user = fief_user )
565
+ elif api_key :
566
+ # API key authentication
567
+ user_and_key = get_user_by_api_key (api_key )
568
+ if user_and_key is None :
569
+ raise HTTPException (status_code = 403 , detail = "Invalid API key" )
570
+
571
+ user , api_key_info = user_and_key
572
+ return AuthInfo (auth_type = "api_key" , user = user , api_key_info = api_key_info )
573
+ else :
574
+ # No authentication provided - this is OK for public devices
575
+ return None
576
+
577
+
534
578
async def flexible_auth (
535
579
fief_user : Optional [FiefUserInfo ] = Depends (get_cached_fief_user_optional ()),
536
580
api_key : Optional [str ] = Header (None , alias = "X-API-Key" ),
@@ -554,10 +598,19 @@ async def flexible_auth(
554
598
raise HTTPException (status_code = 401 , detail = "Authentication required" )
555
599
556
600
557
- def validate_device_access_flexible (auth_info : AuthInfo , device_id : str ) -> bool :
601
+ def validate_device_access_flexible (auth_info : Optional [ AuthInfo ] , device_id : str ) -> bool :
558
602
"""
559
603
Validate device access for flexible authentication.
604
+ Handles public devices (no auth required) and private devices (auth required).
560
605
"""
606
+ # First check if the device is public
607
+ if is_device_public (device_id ):
608
+ return True
609
+
610
+ # Device is private, authentication is required
611
+ if auth_info is None :
612
+ return False
613
+
561
614
if auth_info .auth_type == "fief" :
562
615
# Use existing Fief-based validation
563
616
return device_id_is_allowed_for_user (device_id , user = auth_info .fief_user )
0 commit comments