microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/docs/sso/oauthflowbot-trace-2026-04-22-summary.md
355lines ยท modecode
| 1 | # ๐ OAuthFlowBot Trace Summary (Popup Fallback) |
| 2 | |
| 3 | **Date**: 2026-04-22 03:12:00 UTC |
| 4 | **Bot**: my-bot-sso (AppID: `e3cb1c84-14e3-419c-b39c-1c06097b55fd`) |
| 5 | **User**: Rido (aadObjectId: `03500558-e554-416c-90c3-a061cdcd012b`) |
| 6 | **Connection**: `teamsgraph` (Azure AD v2, no SSO โ popup fallback) |
| 7 | **Platform**: ๐ Web (Teams) |
| 8 | **SDK Version**: `0.0.1-alpha-0107-g1c503584a7` |
| 9 | **Result**: โ
SUCCESS (login graph + my ad user + logout graph) |
| 10 | |
| 11 | > **Key difference from SsoBot**: This connection does not have `tokenExchangeResource` (SSO not configured). |
| 12 | > Login completes via **popup sign-in** + `signin/verifyState` instead of silent `signin/tokenExchange`. |
| 13 | |
| 14 | ### ๐ Identity Reference |
| 15 | |
| 16 | | Identity | MRI / Value | |
| 17 | |----------|-------------| |
| 18 | | User MRI | `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` | |
| 19 | | User AAD ObjectId | `03500558-e554-416c-90c3-a061cdcd012b` | |
| 20 | | Bot MRI | `28:e3cb1c84-14e3-419c-b39c-1c06097b55fd` | |
| 21 | | Bot AppId | `e3cb1c84-14e3-419c-b39c-1c06097b55fd` | |
| 22 | | Tenant Id | `3f3d1cea-7a18-41af-872b-cfbbd5140984` | |
| 23 | | Conversation Id | `a:1xH4HncZ6lyZnMVYp9rTKoRyS44qDCikYZ1u-Q0VNmZqyceL6nKfe5ZKG9CqOi2WuXNDJyLBAaDgVChKMxKFPlAZ5bsy0_8RhvPYYi5ZJJKCiia_SEd_e8WJVlSHOIM3Z` | |
| 24 | | Service URL | `https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/` | |
| 25 | |
| 26 | --- |
| 27 | |
| 28 | ## ๐ Login Flow (Popup Fallback โ no SSO) |
| 29 | |
| 30 | ### Step 1 โ User sends "login graph" message |
| 31 | |
| 32 | ๐ฅ **INCOMING** `POST http://localhost:3978/api/messages` |
| 33 | - **Activity**: |
| 34 | - `type`: `message` |
| 35 | - `id`: `1776827520098` |
| 36 | - `channelId`: `msteams` |
| 37 | - `text`: `"login graph"` |
| 38 | - `textFormat`: `plain` |
| 39 | - `timestamp`: `2026-04-22T03:12:00.1176725Z` |
| 40 | - `from.id`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 41 | - `from.name`: `Rido` |
| 42 | - `from.aadObjectId`: `03500558-e554-416c-90c3-a061cdcd012b` |
| 43 | - `recipient.id`: `28:e3cb1c84-14e3-419c-b39c-1c06097b55fd` *(Bot MRI)* |
| 44 | - `recipient.name`: `my-bot-sso` |
| 45 | - `conversation.id`: `a:1xH4HncZ6ly...OIM3Z` |
| 46 | - `conversation.conversationType`: `personal` |
| 47 | - `conversation.tenantId`: `3f3d1cea-7a18-41af-872b-cfbbd5140984` |
| 48 | - `serviceUrl`: `https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/` |
| 49 | - `entities[0]`: `{ locale: "en-US", country: "US", platform: "Web", timezone: "America/Los_Angeles", type: "clientInfo" }` |
| 50 | - `MSCV`: `4+YxTIufBEq78SeAVHsSdQ.1.1.1.485196365.1.1` |
| 51 | - ๐ก๏ธ JWT validated (AzureAd scheme) |
| 52 | - ๐ Route: `message/(?i)^login graph$` |
| 53 | |
| 54 | ### Step 2 โ Silent token check (no cached token) |
| 55 | |
| 56 | ๐ค **OUTGOING** `GET https://token.botframework.com/api/usertoken/GetToken` |
| 57 | - **Query Parameters**: |
| 58 | - `userid`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 59 | - `connectionName`: `teamsgraph` |
| 60 | - `channelId`: `msteams` |
| 61 | - **Request Body**: `(null)` |
| 62 | - **Auth**: ๐ MSAL AcquireTokenForClient (source: IdentityProvider) โ first token from AAD |
| 63 | - โ **Response**: `404` โ no cached user token |
| 64 | |
| 65 | ### Step 3 โ Get sign-in resource |
| 66 | |
| 67 | ๐ค **OUTGOING** `GET https://token.botframework.com/api/botsignin/GetSignInResource` |
| 68 | - **Query Parameters**: |
| 69 | - `state`: base64-encoded JSON: |
| 70 | ```json |
| 71 | { |
| 72 | "ConnectionName": "teamsgraph", |
| 73 | "Conversation": { |
| 74 | "ActivityId": "1776827520098", |
| 75 | "Bot": { "Id": "28:e3cb1c84-14e3-419c-b39c-1c06097b55fd" }, |
| 76 | "ChannelId": "msteams", |
| 77 | "Conversation": { "Id": "a:1xH4HncZ6ly...OIM3Z" }, |
| 78 | "ServiceUrl": "https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/", |
| 79 | "User": { "Id": "29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ" } |
| 80 | }, |
| 81 | "MsAppId": "e3cb1c84-14e3-419c-b39c-1c06097b55fd" |
| 82 | } |
| 83 | ``` |
| 84 | - **Request Body**: `(null)` |
| 85 | - **Auth**: ๐ MSAL from cache |
| 86 | - โ
**Response**: `200` โ returns signInLink + tokenPostResource, **โ ๏ธ NO tokenExchangeResource** (SSO not configured) |
| 87 | |
| 88 | ### Step 4 โ Send OAuthCard to user (popup only, no SSO) |
| 89 | |
| 90 | ๐ค **OUTGOING** `POST https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/v3/conversations/a%3A1xH4HncZ6ly...OIM3Z/activities/1776827520098` |
| 91 | - **Auth**: ๐ MSAL from cache |
| 92 | - **Request Body**: |
| 93 | ```json |
| 94 | { |
| 95 | "from": { |
| 96 | "id": "28:e3cb1c84-14e3-419c-b39c-1c06097b55fd", |
| 97 | "name": "my-bot-sso" |
| 98 | }, |
| 99 | "recipient": { |
| 100 | "id": "29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ", |
| 101 | "name": "Rido", |
| 102 | "aadObjectId": "03500558-e554-416c-90c3-a061cdcd012b" |
| 103 | }, |
| 104 | "conversation": { |
| 105 | "tenantId": "3f3d1cea-7a18-41af-872b-cfbbd5140984", |
| 106 | "conversationType": "personal", |
| 107 | "id": "a:1xH4HncZ6ly...OIM3Z" |
| 108 | }, |
| 109 | "attachments": [{ |
| 110 | "contentType": "application/vnd.microsoft.card.oauth", |
| 111 | "content": { |
| 112 | "text": "Please Sign In", |
| 113 | "connectionName": "teamsgraph", |
| 114 | "buttons": [{ |
| 115 | "type": "signin", |
| 116 | "title": "Sign In", |
| 117 | "value": "https://token.botframework.com/api/oauth/signin?signin=02706e367e884e8ea4e86472cbd71932" |
| 118 | }], |
| 119 | "tokenPostResource": { |
| 120 | "SasUrl": "https://token.botframework.com/api/sas/postToken?expiry=1776827583&id=key2&state=02706e367e884e8ea4e86472cbd71932&hmac=..." |
| 121 | } |
| 122 | } |
| 123 | }], |
| 124 | "type": "message", |
| 125 | "channelId": "msteams", |
| 126 | "serviceUrl": "https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/", |
| 127 | "replyToId": "1776827520098" |
| 128 | } |
| 129 | ``` |
| 130 | > **Note**: `tokenExchangeResource` is **omitted** (not sent as null). This is the fix applied in this run โ previously it was serialized as `"tokenExchangeResource": null` which caused Teams to reject with `BadRequest`. |
| 131 | - โ
**Response**: `200` |
| 132 | |
| 133 | ๐ **HTTP Response to Teams**: `200` |
| 134 | |
| 135 | ### Step 5 โ User completes popup sign-in, Teams sends signin/verifyState |
| 136 | |
| 137 | ๐ฅ **INCOMING** `POST http://localhost:3978/api/messages` |
| 138 | - **Activity**: |
| 139 | - `type`: `invoke` |
| 140 | - `name`: `signin/verifyState` |
| 141 | - `id`: `f:7d1e8ec2-5897-396e-aa7b-f579ad2fac9f` |
| 142 | - `channelId`: `msteams` |
| 143 | - `timestamp`: `2026-04-22T03:12:09.445Z` |
| 144 | - `from.id`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 145 | - `from.name`: `Rido` |
| 146 | - `from.aadObjectId`: `03500558-e554-416c-90c3-a061cdcd012b` |
| 147 | - `recipient.id`: `28:e3cb1c84-14e3-419c-b39c-1c06097b55fd` *(Bot MRI)* |
| 148 | - `recipient.name`: `my-bot-sso` |
| 149 | - `conversation.id`: `a:1xH4HncZ6ly...OIM3Z` |
| 150 | - `conversation.conversationType`: `personal` |
| 151 | - `conversation.tenantId`: `3f3d1cea-7a18-41af-872b-cfbbd5140984` |
| 152 | - `serviceUrl`: `https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/` |
| 153 | - `replyToId`: `1776827524158` |
| 154 | - `channelData.source.name`: `message` |
| 155 | - `channelData.legacy.replyToId`: `1:1m2Cdy7qBU0p3417d81g04kt7MXJrjQC-X21CRiZVWzk` |
| 156 | - `value`: `{ "state": "745254" }` *(verification code from popup)* |
| 157 | - `MSCV`: `FvSbzMYrUE+OReNyK+4lyg.1.3` |
| 158 | - ๐ก๏ธ JWT validated (AzureAd scheme) |
| 159 | - ๐ Route: `invoke/signin/verifyState` |
| 160 | |
| 161 | ### Step 6 โ Verify state and get token |
| 162 | |
| 163 | ๐ค **OUTGOING** `GET https://token.botframework.com/api/usertoken/GetToken` |
| 164 | - **Query Parameters**: |
| 165 | - `userid`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 166 | - `connectionName`: `teamsgraph` |
| 167 | - `channelId`: `msteams` |
| 168 | - `code`: `745254` *(verification code from verifyState)* |
| 169 | - **Request Body**: `(null)` |
| 170 | - **Auth**: ๐ MSAL from cache |
| 171 | - โ
**Response**: `200` โ user token returned |
| 172 | |
| 173 | ### Step 7 โ ๐ OnSignInComplete fires, bot sends confirmation |
| 174 | |
| 175 | ๐ค **OUTGOING** `POST https://smba.trafficmanager.net/amer/.../v3/conversations/a%3A1xH4HncZ6ly...OIM3Z/activities/f:7d1e8ec2-5897-396e-aa7b-f579ad2fac9f` |
| 176 | - **Auth**: ๐ MSAL from cache |
| 177 | - **Request Body**: |
| 178 | ```json |
| 179 | { |
| 180 | "from": { "id": "28:e3cb1c84-14e3-419c-b39c-1c06097b55fd", "name": "my-bot-sso" }, |
| 181 | "conversation": { "tenantId": "3f3d1cea-...", "conversationType": "personal", "id": "a:1xH4HncZ6ly...OIM3Z" }, |
| 182 | "type": "message", |
| 183 | "channelId": "msteams", |
| 184 | "serviceUrl": "https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/", |
| 185 | "replyToId": "f:7d1e8ec2-5897-396e-aa7b-f579ad2fac9f", |
| 186 | "text": "Connected to Microsoft Graph (teamsgraph)!", |
| 187 | "textFormat": "plain" |
| 188 | } |
| 189 | ``` |
| 190 | - โ
**Response**: `201 Created` |
| 191 | |
| 192 | ๐ **Invoke Response**: `200` (body: null) |
| 193 | |
| 194 | --- |
| 195 | |
| 196 | ## ๐ค "my ad user" Flow (token cached) |
| 197 | |
| 198 | ### Step 8 โ User sends "my ad user" message |
| 199 | |
| 200 | ๐ฅ **INCOMING** `POST http://localhost:3978/api/messages` |
| 201 | - **Activity**: |
| 202 | - `type`: `message` |
| 203 | - `id`: `1776827541160` |
| 204 | - `text`: `"my ad user"` |
| 205 | - `textFormat`: `plain` |
| 206 | - `timestamp`: `2026-04-22T03:12:21.179708Z` |
| 207 | - `from.id`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 208 | - `from.aadObjectId`: `03500558-e554-416c-90c3-a061cdcd012b` |
| 209 | - `recipient.id`: `28:e3cb1c84-14e3-419c-b39c-1c06097b55fd` *(Bot MRI)* |
| 210 | - `attachments[0]`: `{ contentType: "text/html", content: "<div><span style=\"font-size:inherit\">my ad user</span></div>" }` |
| 211 | - `MSCV`: `eTD3PgxXhEiK0mFFc7QunQ.1.1.1.485974193.1.1` |
| 212 | - ๐ Route: `message/(?i)^my ad user` |
| 213 | |
| 214 | ### Step 9 โ Silent token check (token exists) |
| 215 | |
| 216 | ๐ค **OUTGOING** `GET https://token.botframework.com/api/usertoken/GetToken` |
| 217 | - **Query Parameters**: |
| 218 | - `userid`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 219 | - `connectionName`: `teamsgraph` |
| 220 | - `channelId`: `msteams` |
| 221 | - **Request Body**: `(null)` |
| 222 | - **Auth**: ๐ MSAL from cache |
| 223 | - โ
**Response**: `200` โ cached user token returned |
| 224 | |
| 225 | ### Step 10 โ Call Graph API with token |
| 226 | |
| 227 | ๐ค **OUTGOING** `GET https://graph.microsoft.com/v1.0/me` |
| 228 | - **Auth**: `Authorization: Bearer {user_token}` |
| 229 | - โ
**Response**: `200` โ `{ displayName: "Rido", mail: "rido@teamssdk.onmicrosoft.com", id: "03500558-e554-416c-90c3-a061cdcd012b" }` |
| 230 | |
| 231 | ### Step 11 โ Send profile result |
| 232 | |
| 233 | ๐ค **OUTGOING** `POST https://smba.trafficmanager.net/amer/.../v3/conversations/a%3A1xH4HncZ6ly...OIM3Z/activities/1776827541160` |
| 234 | - **Auth**: ๐ MSAL from cache |
| 235 | - **Request Body**: |
| 236 | ```json |
| 237 | { |
| 238 | "from": { "id": "28:e3cb1c84-14e3-419c-b39c-1c06097b55fd", "name": "my-bot-sso" }, |
| 239 | "conversation": { "tenantId": "3f3d1cea-...", "conversationType": "personal", "id": "a:1xH4HncZ6ly...OIM3Z" }, |
| 240 | "type": "message", |
| 241 | "channelId": "msteams", |
| 242 | "serviceUrl": "https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/", |
| 243 | "replyToId": "1776827541160", |
| 244 | "text": "Your Azure AD user :\n```json\n{\"displayName\":\"Rido\",\"givenName\":\"Rido\",\"jobTitle\":\"Not an architect\",\"mail\":\"rido@teamssdk.onmicrosoft.com\",...}\n```", |
| 245 | "textFormat": "plain" |
| 246 | } |
| 247 | ``` |
| 248 | - โ
**Response**: `201 Created` |
| 249 | |
| 250 | --- |
| 251 | |
| 252 | ## ๐ช Logout Flow |
| 253 | |
| 254 | ### Step 12 โ User sends "logout graph" message |
| 255 | |
| 256 | ๐ฅ **INCOMING** `POST http://localhost:3978/api/messages` |
| 257 | - **Activity**: |
| 258 | - `type`: `message` |
| 259 | - `id`: `1776827548949` |
| 260 | - `text`: `"logout graph"` |
| 261 | - `textFormat`: `plain` |
| 262 | - `timestamp`: `2026-04-22T03:12:28.9762671Z` |
| 263 | - `from.id`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 264 | - `from.aadObjectId`: `03500558-e554-416c-90c3-a061cdcd012b` |
| 265 | - `recipient.id`: `28:e3cb1c84-14e3-419c-b39c-1c06097b55fd` *(Bot MRI)* |
| 266 | - `MSCV`: `ymRk2x/XZ0CFG0QGeNHrOg.1.1.1.486335532.1.1` |
| 267 | - ๐ Route: `message/(?i)^logout graph$` |
| 268 | |
| 269 | ### Step 13 โ Sign out user |
| 270 | |
| 271 | ๐ค **OUTGOING** `DELETE https://token.botframework.com/api/usertoken/SignOut` |
| 272 | - **Query Parameters**: |
| 273 | - `userid`: `29:1cgsv1oFLAoTflZ-AxCZ_erWK6f4AqDSzZGpJOS7FuyfB8gn-g9bWmVM8usvvrv2e0atWV6wxZOQCn-xntjVrrQ` *(User MRI)* |
| 274 | - `connectionName`: `teamsgraph` |
| 275 | - `channelId`: `msteams` |
| 276 | - **Request Body**: `(null)` |
| 277 | - **Auth**: ๐ MSAL from cache |
| 278 | - โ
**Response**: `200` โ token revoked |
| 279 | |
| 280 | ### Step 14 โ Send confirmation |
| 281 | |
| 282 | ๐ค **OUTGOING** `POST https://smba.trafficmanager.net/amer/.../v3/conversations/a%3A1xH4HncZ6ly...OIM3Z/activities/1776827548949` |
| 283 | - **Auth**: ๐ MSAL from cache |
| 284 | - **Request Body**: |
| 285 | ```json |
| 286 | { |
| 287 | "from": { "id": "28:e3cb1c84-14e3-419c-b39c-1c06097b55fd", "name": "my-bot-sso" }, |
| 288 | "conversation": { "tenantId": "3f3d1cea-...", "conversationType": "personal", "id": "a:1xH4HncZ6ly...OIM3Z" }, |
| 289 | "type": "message", |
| 290 | "channelId": "msteams", |
| 291 | "serviceUrl": "https://smba.trafficmanager.net/amer/3f3d1cea-7a18-41af-872b-cfbbd5140984/", |
| 292 | "replyToId": "1776827548949", |
| 293 | "text": "Signed out from Graph.", |
| 294 | "textFormat": "plain" |
| 295 | } |
| 296 | ``` |
| 297 | - โ
**Response**: `201 Created` |
| 298 | |
| 299 | --- |
| 300 | |
| 301 | ## ๐ Request Summary Table |
| 302 | |
| 303 | | # | Direction | Method | Endpoint | Status | Purpose | |
| 304 | |---|-----------|--------|----------|--------|---------| |
| 305 | | 1 | ๐ฅ โฌ๏ธ IN | POST | `/api/messages` | โ
200 | ๐ฌ "login graph" message | |
| 306 | | 2 | ๐ค โฌ๏ธ OUT | GET | `token.botframework.com/api/usertoken/GetToken` | โ 404 | ๐ Silent token check (miss) | |
| 307 | | 3 | ๐ค โฌ๏ธ OUT | GET | `token.botframework.com/api/botsignin/GetSignInResource` | โ
200 | ๐ Get sign-in resource (no tokenExchangeResource) | |
| 308 | | 4 | ๐ค โฌ๏ธ OUT | POST | `smba.trafficmanager.net/.../activities` | โ
200 | ๐ Send OAuthCard (popup only, no SSO) | |
| 309 | | 5 | ๐ฅ โฌ๏ธ IN | POST | `/api/messages` | โ
200 | ๐ signin/verifyState invoke (code=745254) | |
| 310 | | 6 | ๐ค โฌ๏ธ OUT | GET | `token.botframework.com/api/usertoken/GetToken` | โ
200 | ๐ Verify state + get token (code=745254) | |
| 311 | | 7 | ๐ค โฌ๏ธ OUT | POST | `smba.trafficmanager.net/.../activities` | โ
201 | ๐ "Connected to Microsoft Graph!" | |
| 312 | | 8 | ๐ฅ โฌ๏ธ IN | POST | `/api/messages` | โ
200 | ๐ฌ "my ad user" message | |
| 313 | | 9 | ๐ค โฌ๏ธ OUT | GET | `token.botframework.com/api/usertoken/GetToken` | โ
200 | ๐ Silent token check (hit) | |
| 314 | | 10 | ๐ค โฌ๏ธ OUT | GET | `graph.microsoft.com/v1.0/me` | โ
200 | ๐ค Graph API call | |
| 315 | | 11 | ๐ค โฌ๏ธ OUT | POST | `smba.trafficmanager.net/.../activities` | โ
201 | ๐ Profile response | |
| 316 | | 12 | ๐ฅ โฌ๏ธ IN | POST | `/api/messages` | โ
200 | ๐ฌ "logout graph" message | |
| 317 | | 13 | ๐ค โฌ๏ธ OUT | DELETE | `token.botframework.com/api/usertoken/SignOut` | โ
200 | ๐ช Revoke token | |
| 318 | | 14 | ๐ค โฌ๏ธ OUT | POST | `smba.trafficmanager.net/.../activities` | โ
201 | ๐ฌ "Signed out from Graph." | |
| 319 | |
| 320 | ## ๐ User MRI Usage Across Requests |
| 321 | |
| 322 | | Request | Where User MRI appears | Format | |
| 323 | |---------|----------------------|--------| |
| 324 | | Step 1 (incoming message) | `activity.from.id` | `29:1cgsv1oFLAoTflZ-...` | |
| 325 | | Step 2 (GetToken) | `?userid=` query param | URL-encoded: `29%3A1cgsv1oFLAoTflZ-...` | |
| 326 | | Step 3 (GetSignInResource) | `state.Conversation.User.Id` (base64 JSON) | `29:1cgsv1oFLAoTflZ-...` | |
| 327 | | Step 4 (Send OAuthCard) | `recipient.id` (reply to user) | `29:1cgsv1oFLAoTflZ-...` | |
| 328 | | Step 5 (verifyState invoke) | `activity.from.id` | `29:1cgsv1oFLAoTflZ-...` | |
| 329 | | Step 6 (GetToken + code) | `?userid=` query param | URL-encoded: `29%3A1cgsv1oFLAoTflZ-...` | |
| 330 | | Step 9 (GetToken cached) | `?userid=` query param | URL-encoded: `29%3A1cgsv1oFLAoTflZ-...` | |
| 331 | | Step 13 (SignOut) | `?userid=` query param | URL-encoded: `29%3A1cgsv1oFLAoTflZ-...` | |
| 332 | |
| 333 | > **Note**: The User MRI (`29:...`) is the Teams-specific identifier. It is used as `userid` in all Token Bot Service calls (GetToken, SignOut) and appears in `from.id` on incoming activities and `recipient.id` on outgoing replies. The AAD ObjectId (`03500558-...`) appears separately in `from.aadObjectId` and in the outgoing `recipient.aadObjectId`. |
| 334 | |
| 335 | --- |
| 336 | |
| 337 | ## ๐ vs SsoBot: Key Differences |
| 338 | |
| 339 | | Aspect | SsoBot (`sso` connection) | OAuthFlowBot (`teamsgraph` connection) | |
| 340 | |--------|--------------------------|----------------------------------------| |
| 341 | | SSO support | โ
`tokenExchangeResource` present | โ `tokenExchangeResource` omitted | |
| 342 | | Sign-in invoke | `signin/tokenExchange` (silent) | `signin/verifyState` (popup + code) | |
| 343 | | Token acquisition | `POST /api/usertoken/exchange` with SSO JWT | `GET /api/usertoken/GetToken` with `code` param | |
| 344 | | User interaction | None (fully silent) | Popup window + consent | |
| 345 | | OAuthFlow API | Context API (`context.SignIn()`) | Instance API (`graphAuth.SignInAsync(context)`) | |
| 346 | | verifyState value | N/A | `{ "state": "745254" }` | |
| 347 | | tokenExchange value | `{ id, connectionName, token }` | N/A | |
| 348 | |
| 349 | ## ๐ Bug Fixed During This Run |
| 350 | |
| 351 | **Issue**: `OAuthCard` serialized `"tokenExchangeResource": null` explicitly in JSON. Teams rejected this with `BadRequest: {"error":{"code":"ServiceError","message":"Unknown"}}`. |
| 352 | |
| 353 | **Fix**: Added `[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]` to `TokenExchangeResource` and `TokenPostResource` properties in `OAuthCard.cs`. When null, these properties are now omitted from the JSON instead of being sent as explicit nulls. |
| 354 | |
| 355 | **File**: `src/Microsoft.Teams.Apps/Schema/OAuthCard.cs` |
| 356 | |