@@ -29,28 +29,41 @@ def __init__(
2929 api_key : Optional [str ] = None ,
3030 api_secret : Optional [str ] = None ,
3131 * ,
32+ token : Optional [str ] = None ,
3233 timeout : Optional [aiohttp .ClientTimeout ] = None ,
3334 session : Optional [aiohttp .ClientSession ] = None ,
3435 failover : bool = True ,
3536 ):
3637 """Create a new LiveKitAPI instance.
3738
39+ Authenticate with an API key and secret (recommended for backend use).
40+ For token auth (client-side use, where the API secret must not be
41+ exposed), prefer the :meth:`with_token` constructor.
42+
3843 Args:
3944 url: LiveKit server URL (read from `LIVEKIT_URL` environment variable if not provided)
4045 api_key: API key (read from `LIVEKIT_API_KEY` environment variable if not provided)
4146 api_secret: API secret (read from `LIVEKIT_API_SECRET` environment variable if not provided)
47+ token: Pre-signed access token (read from `LIVEKIT_TOKEN` environment variable if not provided)
4248 timeout: Request timeout (default: 10 seconds)
4349 session: aiohttp.ClientSession instance to use for requests, if not provided, a new one will be created
4450 """
4551 url = url or os .getenv ("LIVEKIT_URL" )
46- api_key = api_key or os .getenv ("LIVEKIT_API_KEY" )
47- api_secret = api_secret or os .getenv ("LIVEKIT_API_SECRET" )
52+
53+ # Only fall back to environment credentials when none were provided
54+ # explicitly, so an ambient LIVEKIT_TOKEN can't silently override an
55+ # explicit api_key/secret (or vice versa).
56+ if not token and not api_key and not api_secret :
57+ token = os .getenv ("LIVEKIT_TOKEN" )
58+ if not token and not api_key and not api_secret :
59+ api_key = os .getenv ("LIVEKIT_API_KEY" )
60+ api_secret = os .getenv ("LIVEKIT_API_SECRET" )
4861
4962 if not url :
5063 raise ValueError ("url must be set" )
5164
52- if not api_key or not api_secret :
53- raise ValueError ("api_key and api_secret must be set" )
65+ if not token and ( not api_key or not api_secret ) :
66+ raise ValueError ("either token, or api_key and api_secret, must be set" )
5467
5568 self ._custom_session = True
5669 self ._session = session
@@ -60,14 +73,51 @@ def __init__(
6073 timeout = aiohttp .ClientTimeout (total = 10 )
6174 self ._session = aiohttp .ClientSession (timeout = timeout )
6275
63- self ._room = RoomService (self ._session , url , api_key , api_secret , failover )
64- self ._ingress = IngressService (self ._session , url , api_key , api_secret , failover )
65- self ._egress = EgressService (self ._session , url , api_key , api_secret , failover )
66- self ._sip = SipService (self ._session , url , api_key , api_secret , failover )
67- self ._agent_dispatch = AgentDispatchService (
68- self ._session , url , api_key , api_secret , failover
69- )
70- self ._connector = ConnectorService (self ._session , url , api_key , api_secret , failover )
76+ # In token mode there is no key/secret; pass empty strings and rely on
77+ # the token, injected into each service below.
78+ key = api_key or ""
79+ secret = api_secret or ""
80+ self ._room = RoomService (self ._session , url , key , secret , failover )
81+ self ._ingress = IngressService (self ._session , url , key , secret , failover )
82+ self ._egress = EgressService (self ._session , url , key , secret , failover )
83+ self ._sip = SipService (self ._session , url , key , secret , failover )
84+ self ._agent_dispatch = AgentDispatchService (self ._session , url , key , secret , failover )
85+ self ._connector = ConnectorService (self ._session , url , key , secret , failover )
86+
87+ if token :
88+ for svc in (
89+ self ._room ,
90+ self ._ingress ,
91+ self ._egress ,
92+ self ._sip ,
93+ self ._agent_dispatch ,
94+ self ._connector ,
95+ ):
96+ svc ._token = token
97+
98+ @classmethod
99+ def with_token (
100+ cls ,
101+ token : str ,
102+ url : Optional [str ] = None ,
103+ * ,
104+ timeout : Optional [aiohttp .ClientTimeout ] = None ,
105+ session : Optional [aiohttp .ClientSession ] = None ,
106+ failover : bool = True ,
107+ ) -> "LiveKitAPI" :
108+ """Create a LiveKitAPI authenticated with a pre-signed token.
109+
110+ The token is sent verbatim and must already carry the grants for the calls
111+ it's used with. Since it needs no secret, this is suitable for client-side
112+ use. `url` falls back to the `LIVEKIT_URL` environment variable.
113+
114+ Args:
115+ token: Pre-signed access token
116+ url: LiveKit server URL (read from `LIVEKIT_URL` if not provided)
117+ timeout: Request timeout (default: 10 seconds)
118+ session: aiohttp.ClientSession to use; a new one is created if omitted
119+ """
120+ return cls (url , token = token , timeout = timeout , session = session , failover = failover )
71121
72122 @property
73123 def agent_dispatch (self ) -> AgentDispatchService :
0 commit comments