Skip to content

Commit ddd472c

Browse files
Changing usage of recipient.id to recipient.agentic_user_id for agentic auth flows (#173)
* Changing usage of upn property to agentic_user_id * Fixing tests * commit * Commit * Documenting the unexpected behavior needed to get this thing to work * Fixing subchannel serialization * Addressing lingering PR comment
1 parent 17fbf28 commit ddd472c

File tree

8 files changed

+60
-49
lines changed

8 files changed

+60
-49
lines changed

libraries/microsoft-agents-activity/microsoft_agents/activity/activity.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def _serialize_sub_channel_data(
253253
product_info = entity
254254
break
255255

256-
# maintain consistency between ProductInfo entity and sub channel
256+
# self.channel_id is the source of truth for serialization
257257
if self.channel_id and self.channel_id.sub_channel:
258258
if product_info and product_info.get("id") != self.channel_id.sub_channel:
259259
raise Exception(
@@ -268,6 +268,13 @@ def _serialize_sub_channel_data(
268268
"id": self.channel_id.sub_channel,
269269
}
270270
)
271+
272+
# simply serialized channelId value in Activity and relatesTo
273+
if "channelId" in serialized:
274+
serialized["channelId"] = self.channel_id.channel
275+
elif "channel_id" in serialized:
276+
serialized["channel_id"] = self.channel_id.channel
277+
271278
elif product_info: # remove productInfo entity if sub_channel is not set
272279
del serialized["entities"][i]
273280
if not serialized["entities"]: # after removal above, list may be empty
@@ -777,7 +784,7 @@ def get_agentic_instance_id(self) -> Optional[str]:
777784
return self.recipient.agentic_app_id
778785

779786
def get_agentic_user(self) -> Optional[str]:
780-
"""Gets the agentic user (UPN) from the context if it's an agentic request."""
787+
"""Gets the agentic user (agenticUserId) from the context if it's an agentic request."""
781788
if not self.is_agentic_request() or not self.recipient:
782789
return None
783-
return self.recipient.id
790+
return self.recipient.agentic_user_id

libraries/microsoft-agents-authentication-msal/microsoft_agents/authentication/msal/msal_auth.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -311,41 +311,41 @@ async def get_agentic_instance_token(
311311
return agentic_instance_token["access_token"], agent_token_result
312312

313313
async def get_agentic_user_token(
314-
self, agent_app_instance_id: str, upn: str, scopes: list[str]
314+
self, agent_app_instance_id: str, agentic_user_id: str, scopes: list[str]
315315
) -> Optional[str]:
316-
"""Gets the agentic user token for the given agent application instance ID and user principal name and the scopes.
316+
"""Gets the agentic user token for the given agent application instance ID and agentic user Id and the scopes.
317317
318318
:param agent_app_instance_id: The agent application instance ID.
319319
:type agent_app_instance_id: str
320-
:param upn: The user principal name.
321-
:type upn: str
320+
:param agentic_user_id: The agentic user ID.
321+
:type agentic_user_id: str
322322
:param scopes: The scopes to request for the token.
323323
:type scopes: list[str]
324324
:return: The agentic user token, or None if not found.
325325
:rtype: Optional[str]
326326
"""
327-
if not agent_app_instance_id or not upn:
327+
if not agent_app_instance_id or not agentic_user_id:
328328
raise ValueError(
329-
"Agent application instance Id and user principal name must be provided."
329+
"Agent application instance Id and agentic user Id must be provided."
330330
)
331331

332332
logger.info(
333-
"Attempting to get agentic user token from agent_app_instance_id %s and upn %s",
333+
"Attempting to get agentic user token from agent_app_instance_id %s and agentic_user_id %s",
334334
agent_app_instance_id,
335-
upn,
335+
agentic_user_id,
336336
)
337337
instance_token, agent_token = await self.get_agentic_instance_token(
338338
agent_app_instance_id
339339
)
340340

341341
if not instance_token or not agent_token:
342342
logger.error(
343-
"Failed to acquire instance token or agent token for agent_app_instance_id %s and upn %s",
343+
"Failed to acquire instance token or agent token for agent_app_instance_id %s and agentic_user_id %s",
344344
agent_app_instance_id,
345-
upn,
345+
agentic_user_id,
346346
)
347347
raise Exception(
348-
f"Failed to acquire instance token or agent token for agent_app_instance_id {agent_app_instance_id} and upn {upn}"
348+
f"Failed to acquire instance token or agent token for agent_app_instance_id {agent_app_instance_id} and agentic_user_id {agentic_user_id}"
349349
)
350350

351351
authority = (
@@ -359,34 +359,34 @@ async def get_agentic_user_token(
359359
)
360360

361361
logger.info(
362-
"Acquiring agentic user token for agent_app_instance_id %s and upn %s",
362+
"Acquiring agentic user token for agent_app_instance_id %s and agentic_user_id %s",
363363
agent_app_instance_id,
364-
upn,
364+
agentic_user_id,
365365
)
366366
auth_result_payload = instance_app.acquire_token_for_client(
367367
scopes,
368368
data={
369-
"username": upn,
369+
"user_id": agentic_user_id,
370370
"user_federated_identity_credential": instance_token,
371371
"grant_type": "user_fic",
372372
},
373373
)
374374

375375
if not auth_result_payload:
376376
logger.error(
377-
"Failed to acquire agentic user token for agent_app_instance_id %s and upn %s, %s",
377+
"Failed to acquire agentic user token for agent_app_instance_id %s and agentic_user_id %s, %s",
378378
agent_app_instance_id,
379-
upn,
379+
agentic_user_id,
380380
auth_result_payload,
381381
)
382382
return None
383383

384384
access_token = auth_result_payload.get("access_token")
385385
if not access_token:
386386
logger.error(
387-
"Failed to acquire agentic user token for agent_app_instance_id %s and upn %s, %s",
387+
"Failed to acquire agentic user token for agent_app_instance_id %s and agentic_user_id %s, %s",
388388
agent_app_instance_id,
389-
upn,
389+
agentic_user_id,
390390
auth_result_payload,
391391
)
392392
return None

libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/app/oauth/_handlers/agentic_user_authorization.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,20 @@ async def get_agentic_user_token(
118118
connection = self._connection_manager.get_token_provider(
119119
context.identity, "agentic"
120120
)
121-
upn = context.activity.get_agentic_user()
121+
agentic_user_id = context.activity.get_agentic_user()
122122
agentic_instance_id = context.activity.get_agentic_instance_id()
123-
if not upn or not agentic_instance_id:
123+
if not agentic_user_id or not agentic_instance_id:
124124
logger.error(
125-
"Unable to retrieve agentic user token: missing UPN or agentic instance ID. UPN: %s, Agentic Instance ID: %s",
126-
upn,
125+
"Unable to retrieve agentic user token: missing agentic user Id or agentic instance Id. agentic_user_id: %s, Agentic Instance ID: %s",
126+
agentic_user_id,
127127
agentic_instance_id,
128128
)
129129
raise ValueError(
130-
f"Unable to retrieve agentic user token: missing UPN or agentic instance ID. UPN: {upn}, Agentic Instance ID: {agentic_instance_id}"
130+
f"Unable to retrieve agentic user token: missing agentic User Id or agentic instance Id. agentic_user_id: {agentic_user_id}, Agentic Instance ID: {agentic_instance_id}"
131131
)
132132

133133
token = await connection.get_agentic_user_token(
134-
agentic_instance_id, upn, scopes
134+
agentic_instance_id, agentic_user_id, scopes
135135
)
136136
return TokenResponse(token=token) if token else TokenResponse()
137137

libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/access_token_provider_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ async def get_agentic_instance_token(
4343
raise NotImplementedError()
4444

4545
async def get_agentic_user_token(
46-
self, agent_app_instance_id: str, upn: str, scopes: list[str]
46+
self, agent_app_instance_id: str, agentic_user_id: str, scopes: list[str]
4747
) -> Optional[str]:
4848
raise NotImplementedError()

libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/authorization/anonymous_token_provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ async def get_agentic_instance_token(
3333
return "", ""
3434

3535
async def get_agentic_user_token(
36-
self, agent_app_instance_id: str, upn: str, scopes: list[str]
36+
self, agent_app_instance_id: str, agentic_user_id: str, scopes: list[str]
3737
) -> Optional[str]:
3838
return ""

tests/activity/pydantic/test_activity_io.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ def test_channel_id_unset_becomes_set_at_init(self):
132132
activity = Activity(type="message")
133133
activity.channel_id = "channel:sub_channel"
134134
data = activity.model_dump(mode="json", exclude_unset=True, by_alias=True)
135-
assert data["channelId"] == "channel:sub_channel"
135+
assert data["channelId"] == "channel"
136+
assert data["entities"] == [
137+
{"type": EntityTypes.PRODUCT_INFO.value, "id": "sub_channel"}
138+
]
136139

137140
def test_channel_id_unset_at_init_not_included(self):
138141
activity = Activity(type="message")
@@ -156,14 +159,14 @@ def test_product_info_avoids_error_no_parent_channel(self):
156159
Activity(type="message", channel_id="msteams:subchannel"),
157160
{
158161
"type": "message",
159-
"channelId": "msteams:subchannel",
162+
"channelId": "msteams",
160163
"entities": [
161164
{"type": EntityTypes.PRODUCT_INFO.value, "id": "subchannel"}
162165
],
163166
},
164167
{
165168
"type": "message",
166-
"channel_id": "msteams:subchannel",
169+
"channel_id": "msteams",
167170
"entities": [
168171
{"type": EntityTypes.PRODUCT_INFO.value, "id": "subchannel"}
169172
],
@@ -177,15 +180,15 @@ def test_product_info_avoids_error_no_parent_channel(self):
177180
),
178181
{
179182
"type": "message",
180-
"channelId": "msteams:subchannel",
183+
"channelId": "msteams",
181184
"entities": [
182185
{"type": "other"},
183186
{"type": EntityTypes.PRODUCT_INFO.value, "id": "subchannel"},
184187
],
185188
},
186189
{
187190
"type": "message",
188-
"channel_id": "msteams:subchannel",
191+
"channel_id": "msteams",
189192
"entities": [
190193
{"type": "other"},
191194
{"type": EntityTypes.PRODUCT_INFO.value, "id": "subchannel"},
@@ -200,15 +203,15 @@ def test_product_info_avoids_error_no_parent_channel(self):
200203
),
201204
{
202205
"type": "message",
203-
"channelId": "msteams:misc",
206+
"channelId": "msteams",
204207
"entities": [
205208
{"type": "other"},
206209
{"type": EntityTypes.PRODUCT_INFO.value, "id": "misc"},
207210
],
208211
},
209212
{
210213
"type": "message",
211-
"channel_id": "msteams:misc",
214+
"channel_id": "msteams",
212215
"entities": [
213216
{"type": "other"},
214217
{"type": EntityTypes.PRODUCT_INFO.value, "id": "misc"},

tests/activity/test_activity.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -436,15 +436,16 @@ def agentic_role(self, request):
436436
)
437437
def test_is_agentic_request(self, role, expected):
438438
activity = Activity(
439-
type="message", recipient=ChannelAccount(id="bot", name="bot", role=role)
439+
type="message",
440+
recipient=ChannelAccount(agentic_user_id="bot", name="bot", role=role),
440441
)
441442
assert activity.is_agentic_request() == expected
442443

443444
def test_get_agentic_instance_id_is_agentic(self, mocker, agentic_role):
444445
activity = Activity(
445446
type="message",
446447
recipient=ChannelAccount(
447-
id="some_id",
448+
agentic_user_id="some_id",
448449
agentic_app_id=DEFAULTS.agentic_instance_id,
449450
role=agentic_role,
450451
),
@@ -455,7 +456,7 @@ def test_get_agentic_instance_id_not_agentic(self, non_agentic_role):
455456
activity = Activity(
456457
type="message",
457458
recipient=ChannelAccount(
458-
id="some_id",
459+
agentic_user_id="some_id",
459460
agentic_app_id=DEFAULTS.agentic_instance_id,
460461
role=non_agentic_role,
461462
),
@@ -466,7 +467,7 @@ def test_get_agentic_user_is_agentic(self, agentic_role):
466467
activity = Activity(
467468
type="message",
468469
recipient=ChannelAccount(
469-
id=DEFAULTS.agentic_user_id,
470+
agentic_user_id=DEFAULTS.agentic_user_id,
470471
agentic_app_id=DEFAULTS.agentic_instance_id,
471472
role=agentic_role,
472473
),
@@ -477,7 +478,7 @@ def test_get_agentic_user_not_agentic(self, non_agentic_role):
477478
activity = Activity(
478479
type="message",
479480
recipient=ChannelAccount(
480-
id=DEFAULTS.agentic_user_id,
481+
agentic_user_id=DEFAULTS.agentic_user_id,
481482
agentic_app_id=DEFAULTS.agentic_instance_id,
482483
role=non_agentic_role,
483484
),

tests/hosting_core/app/_oauth/_handlers/test_agentic_user_authorization.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ async def test_get_agentic_instance_token_not_agentic(
8585
activity = Activity(
8686
type="message",
8787
recipient=ChannelAccount(
88-
id=DEFAULTS.agentic_user_id,
88+
agentic_user_id=DEFAULTS.agentic_user_id,
8989
agentic_app_id=DEFAULTS.agentic_instance_id,
9090
role=non_agentic_role,
9191
),
@@ -100,7 +100,7 @@ async def test_get_agentic_user_token_not_agentic(
100100
activity = Activity(
101101
type="message",
102102
recipient=ChannelAccount(
103-
id=DEFAULTS.agentic_user_id,
103+
agentic_user_id=DEFAULTS.agentic_user_id,
104104
agentic_app_id=DEFAULTS.agentic_instance_id,
105105
role=non_agentic_role,
106106
),
@@ -145,7 +145,7 @@ async def test_get_agentic_instance_token_is_agentic(
145145
activity = Activity(
146146
type="message",
147147
recipient=ChannelAccount(
148-
id="some_id",
148+
agentic_user_id="some_id",
149149
agentic_app_id=DEFAULTS.agentic_instance_id,
150150
role=agentic_role,
151151
),
@@ -177,7 +177,7 @@ async def test_get_agentic_user_token_is_agentic(
177177
activity = Activity(
178178
type="message",
179179
recipient=ChannelAccount(
180-
id="some_id",
180+
agentic_user_id="some_id",
181181
agentic_app_id=DEFAULTS.agentic_instance_id,
182182
role=agentic_role,
183183
),
@@ -221,7 +221,7 @@ async def test_sign_in_success(
221221
activity = Activity(
222222
type="message",
223223
recipient=ChannelAccount(
224-
id="some_id",
224+
agentic_user_id="some_id",
225225
agentic_app_id=DEFAULTS.agentic_instance_id,
226226
role=agentic_role,
227227
),
@@ -266,7 +266,7 @@ async def test_sign_in_failure(
266266
activity = Activity(
267267
type="message",
268268
recipient=ChannelAccount(
269-
id="some_id",
269+
agentic_user_id="some_id",
270270
agentic_app_id=DEFAULTS.agentic_instance_id,
271271
role=agentic_role,
272272
),
@@ -311,7 +311,7 @@ async def test_get_refreshed_token_success(
311311
activity = Activity(
312312
type="message",
313313
recipient=ChannelAccount(
314-
id="some_id",
314+
agentic_user_id="some_id",
315315
agentic_app_id=DEFAULTS.agentic_instance_id,
316316
role=agentic_role,
317317
),
@@ -357,7 +357,7 @@ async def test_get_refreshed_token_failure(
357357
activity = Activity(
358358
type="message",
359359
recipient=ChannelAccount(
360-
id="some_id",
360+
agentic_user_id="some_id",
361361
agentic_app_id=DEFAULTS.agentic_instance_id,
362362
role=agentic_role,
363363
),

0 commit comments

Comments
 (0)