2

I'm building an app for Microsoft Teams which requires the user to sign-in inside a bot dialog or message extension. The overall sign-in process works fine. I'm retrieving the token via BotFrameworkAdapter.getUserToken() and if no token is available, the user will be prompted to login based on BotFrameworkAdapter.getSignInLink().

Usually, the token is a JWT. This allows me to decode the claims and verify that it contains all scopes that are currently necessary to use the app. If I'm adding a Graph API permission in the future (e.g. for a new feature), I can therefore prompt the user to sign-in again so that the app doesn't break for users who are already signed in with lesser permissions.

Since recently, tokens are increasingly not issued as plain JWT. Rather, they look similar to an example from the Graph API documentation:

EwAoA8l6BAAU7p9QDpi/D7xJLwsTgCg3TskyTaQAAXu71AU9f4aS4rOK5xoO/SU5HZKSXtCsDe0Pj7uSc5Ug008qTI+a9M1tBeKoTs7tHzhJNSKgk7pm5e8d3oGWXX5shyOG3cKSqgfwuNDnmmPDNDivwmi9kmKqWIC9OQRf8InpYXH7NdUYNwN+jljffvNTewdZz42VPrvqoMH7hSxiG7A1h8leOv4F3Ek/oeJX6U8nnL9nJ5pHLVuPWD0aNnTPTJD8Y4oQTp5zLhDIIfaJCaGcQperULVF7K6yX8MhHxIBwek418rKIp11om0SWBXOYSGOM0rNNN59qNiKwLNK+MPUf7ObcRBN5I5vg8jB7IMoz66jrNmT2uiWCyI8MmYDZgAACPoaZ9REyqke+AE1/x1ZX0w7OamUexKF8YGZiw+cDpT/BP1GsONnwI4a8M7HsBtDgZPRd6/Hfqlq3HE2xLuhYX8bAc1MUr0gP9KuH6HDQNlIV4KaRZWxyRo1wmKHOF5G5wTHrtxg8tnXylMc1PKOtaXIU4JJZ1l4x/7FwhPmg9M86PBPWr5zwUj2CVXC7wWlL/6M89Mlh8yXESMO3AIuAmEMKjqauPrgi9hAdI2oqnLZWCRL9gcHBida1y0DTXQhcwMv1ORrk65VFHtVgYAegrxu3NDoJiDyVaPZxDwTYRGjPII3va8GALAMVy5xou2ikzRvJjW7Gm3XoaqJCTCExN4m5i/Dqc81Gr4uT7OaeypYTUjnwCh7aMhsOTDJehefzjXhlkn//2eik+NivKx/BTJBEdT6MR97Wh/ns/VcK7QTmbjwbU2cwLngT7Ylq+uzhx54R9JMaSLhnw+/nIrcVkG77Hi3neShKeZmnl5DC9PuwIbtNvVge3Q+V0ws2zsL3z7ndz4tTMYFdvR/XbrnbEErTDLWrV6Lc3JHQMs0bYUyTBg5dThwCiuZ1evaT6BlMMLuSCVxdBGzXTBcvGwihFzZbyNoX+52DS5x+RbIEvd6KWOpQ6Ni+1GAawHDdNUiQTQFXRxLSHfc9fh7hE4qcD7PqHGsykYj7A0XqHCjbKKgWSkcAg==

Although this looks like Base64-encoded data and it even says jwt above the snippet in the documentation, this is clearly not a plain JWT. Honestly, I'm not quite sure what it is, however, I assume it is a JWS or a JWT encoded with a nonce.

I'm thinking that I should probably treat this token as opaque, however, because the sign-in (and sign-in link generation) is hidden behind the bot framework I don't see another opportunity for adding permissions to an already deployed application, i.a. verifying that an access token provides the required permissions. Since my app also acts on behalf of the user at a later point in time, it's also not viable to prompt for sign-in after I'm receiving a 403er response from the Graph API.

  1. Is there a way to decode these kinds of tokens or instead make sure that my app will only receive decodable JWTs?
  2. If not, is there an alternative for verifying access token permissions (scopes)?
Nils Mehlhorn
  • 390
  • 2
  • 5
  • 16
  • Hi @nilo we will repro the issue at our end and meanwhile could you please share any sample which you are following. – Ravindra-MSFT Jun 07 '21 at 11:48
  • Thanks, I'm not following a particular sample. I'm calling the functions I've mentioned on a bot adapter that's initialized with credentials from an Azure AD app. – Nils Mehlhorn Jun 08 '21 at 12:10
  • Could you please check with the code in bot adapter from the function your calling the token ( const magicCode = action.state && Number.isInteger(Number(action.state)) ? action.state : ''; const tokenResponse = await context.adapter.getUserToken( context, process.env.connectionName, magicCode ); const graphClient = new SimpleGraphClient(tokenResponse.token); const profile = await graphClient.getMyProfile();) and there is [alternative way](https://jwt.ms/) to verify token. – Ravindra-MSFT Jun 11 '21 at 06:37
  • Please read my question again, your code is not helpful - it's basically just a pre-check for the magic code and a test of the token. As I said, I'm already receiving a token that is accepted by the Graph API. The problem is that sometimes it's not a JWT which you can easily see and even check yourself by inputting the example token on the site that you posted. Also, that's not an alternative way to verify permissions inside of my app - it's just a website that decodes JWTs. – Nils Mehlhorn Jun 12 '21 at 10:25
  • HI @nilo You can go through [here](https://stackoverflow.com/questions/59158389/where-can-i-find-the-public-key-to-verify-the-directline-botframework-com-conver) to decode token. Also, you can check in the https://jwt.ms/ if you are able to decode the token and after decoding you can see the permissions. – Ravindra-MSFT Jun 14 '21 at 10:08
  • Hope this reference is useful. Or else you are still facing with any blocker. – Ravindra-MSFT Jun 15 '21 at 11:36
  • No, this reference is not useful at all, the whole problem is that I'm not receiving a proper JWT. Also, you're linking the same page again, wow ... – Nils Mehlhorn Jun 15 '21 at 13:42
  • 1
    Hi @nilo I have not seen or heard of this strange token behavior. I've asked some internal people, and will get back to you if i learn more about what is happening here. One workaround might be to check if you have received this strange token, and if so: immediately sign the user out by calling signOutUser, then force them to sign in again. – Eric Dahlvang Jul 02 '21 at 03:56
  • Hey @EricDahlvang did you hear back from anyone? Someone has to know what kind of token format is listed in the documentation and why I'm receiving that – Nils Mehlhorn Aug 17 '21 at 14:02
  • I'm sorry, I did not. Maybe ask on that docs page using the feedback button: https://learn.microsoft.com/en-us/graph/auth/auth-concepts#see-also – Eric Dahlvang Aug 17 '21 at 20:17
  • @NilsMehlhorn Did you ever solve this? I think maybe the entire JWT is encrypted rather than using the standard JWT encryption(?) – redcalx Mar 08 '22 at 09:23
  • Didn't solve it directly but implemented fallback code that saves the granted permissions per user in a database after successful login. This way I can fallback to a database lookup when the token is not decodable and eventually force new login where necessary. As mentioned in the original post, I also think it's an encrypted JWT or rather a JWS. – Nils Mehlhorn Mar 09 '22 at 14:08

0 Answers0