microsoft / BotFramework-Services

Microsoft Bot Framework Services
Creative Commons Attribution 4.0 International
38 stars 11 forks source link

Problem Getting Azure B2C OAuth Connection Working #78

Closed silver-stack closed 5 years ago

silver-stack commented 5 years ago

Hello,

My company currently uses Azure B2C to authenticate users and provide access to a .NET Core API via a JavaScript. This is all working fine and currently in productive use.

We decided that it would be great to have a chatbot in .NET core that could call API requests for a different user interface. However, we still need to authenticate users and get a token to call the API and this is where I am having issues.

I have created a new web app bot in Azure, registered the bot in B2C (app entry) and then in the chatbot gone to Settings > 'OAuth Connection Settings' and added a new connection.

Originally I would have expected Azure B2C to be listed, however it is not so I decided to opt for the generic oAuth 2 and I have added all the details here. When I click test connection, it opens the correct login page, I use one of our test accounts, however I get a redirected to the 'https://token.botframework.com/.auth/web/redirect' with a response of 'bad request' (no other error message)..

My assumption is that my Auth URL, Token URL or Refresh URL are incorrect somehow, even though these are similar to the ones I have used in the javascript app to get access to the API's. Please see them below:

Authorization URL: https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/authorize

Token URL: https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/token

Refresh URL: https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/token

Just to note, I am using the client ID and secret from my registered chatbot in Azure B2C in teh connection. I have also tried setting these up using https://.b2clogin.com instead of login.microsoft.com, but I dont even get through to the login page... this must be a configuration with our B2C and cannot really go poking around in there at the minute.

Regarding getting tokens form B2C, I have been using this as a guide: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-access-tokens

Any help you could give would be great as currently we cannot use a chatbot until I get this working.

silver-stack commented 5 years ago

Additionally, when I try this in the emulator using the auth bot sample, I get the sign in button, I click it then a popup opens... but hangs at loading. Please see attached:

image

v-kydela commented 5 years ago

When you set up an OAuth Connection, I believe you want to give it its own Microsoft app registration rather than reusing the client ID and secret from your bot. In that app registration's settings you can configure who is allowed to be authenticated through that app (personal accounts, one specific organization, etc.). This document provides a tutorial for adding authentication to a bot using Azure Active Directory.

It seems like Azure B2C is also called Azure Active Directory B2C, so it might be worthwhile to even try selecting Azure Active Directory v2 rather than Generic Oauth 2. And if you already have an app registration associated with your Azure B2C then you might be able to use that.

v-kydela commented 5 years ago

It looks like there's some documentation about Generic Oauth 2 connections here.

v-kydela commented 5 years ago

@silver-stack - I've just learned that B2C isn't a distinct service from AAD v2, so go ahead and follow the AAD docs

silver-stack commented 5 years ago

Hello @v-kydela, firstly thank you for your quick response, it is much appreciated.

Back to my original post, when I created the new chatbot it was registered in the Azure tenant AADv2 automatically and so a new client ID and secret are created at that point that allow the chatbot channels to authenticate etc. However, so that my B2C customers can authenticate inside the chatbot against my Azure B2C I have registered a new app in the B2C for the chatbot, similar to how the API is registered for which I need to provide access to. Having two sets of client IDs and secrets in this scenario does make it a little difficult to explain, sorry.

I have also just tried setting up a new connection with AADv2 using my Azure B2C details, however the issue here (I think) is that I cannot supply a B2C policy (these are now called User Flows) with the fields that are supplied (see below). Either way I have tried and I get the standard MS AAD login prompt, not my Azure B2C one, so I am not sure that this is the correct path (though I would be more than happy to be corrected).

Bot Connection Details image

My Azure B2C App Details image

Login in screen that I get when logging in via the chatbot emulator: image

Login that I would expect to see: image

I understand that Azure B2C is not used by that many people at the moment, however it would be great if I could use it to get an auth token for my customers so that they can query the API via the chatbot. Any ideas on where I may be going wrong?

v-kydela commented 5 years ago

@silver-stack - I've created a B2C tenant and I can reproduce your issue. To clarify, do you want to be able to configure your bot's OAuth 2.0 connection to use your B2C user flow with that specific UI? Or are you only commenting on the UI discrepancy because you're worried you haven't actually configured the connection to use your B2C app?

silver-stack commented 5 years ago

@v-kydela - thank you again for looking into this. I tried a couple more test earlier today and appeared to get a little further.

So in my previous comment, what I was saying is that if I used the standard AADv2 connection, but used my Azure B2C tenant details I would get redirected to the standard MS login page. I would then try and login with a test B2C user, however I would then get a message informing that the test user does not exist in that tenant. So I dont think this is the right avenue for B2C (see below)

image

Also, this account works fine via our JS based app that uses MSAL to sign-in to our Azure B2C. So I am certain the account is OK. So in answer to your question - I don't think this is configured to connect to use my B2C app.

However, after signing out of everything and clearing my cache I have tested the Generic OAuth 2.0 connection via the OAuth Connection Settings in the chatbot settings (the button 'Test Connection') and the new tab displays my Azure B2C login screen. The URL that it has constructed is the following: https://login.microsoftonline.com/tfp/<tenant ID>/<B2C Policy>/oauth2/v2.0/authorize?client_id=<client ID>&response_type=code&redirect_uri=https%3a%2f%2ftoken.botframework.com%2f.auth%2fweb%2fredirect&scope=<scope>&state=a7c04c340bc64e9a8a67cbb23f9f7ce3

Which looks correct... however I supply the correct credentials and click login and instead of seeing the successful token page I get the following still: image

Maybe its something to do with the generic OAuth 2 token settings? - Though the generic OAuth will be based on a standard and I have followed the documentation, so cant see why this is not working unless its just not supported in this scenario?

v-kydela commented 5 years ago

I actually wasn't able to reproduce that error, but following your guide I was able to get the Generic Oauth 2 connection working in my bot. Let's see what we're doing differently.

OAuth Connection

Client id

This is taken from the Application ID field in your B2C app's properties. It's the equivalent of a Microsoft app ID taken from any other AAD app registration.

image

Client secret

This is generated using the steps in this tutorial.

  1. Select Keys and then click Generate key.
  2. Select Save to view the key. Make note of the App key value. You use the value as the application secret in your application's code.

Authorization/Token/Refresh URL

I followed your lead on this one with https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/authorize for the Authorization URL and https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/token for the Token and Refresh URL's.

For <Tenant ID> I used the URL format (kyleorg.onmicrosoft.com) rather than the GUID format, but using the GUID also seems to work.

<b2c_Policy> is the name of a user flow, like B2C_1_userflow. I created one with this tutorial.

Scopes

I suspect we are differing here. Using the scopes openid offline_access I am able to sign in successfully, but to my astonishment the token returned is empty.

image

Then I found this document which suggests using the client ID itself as a scope.

When I reuse the value from the Client id field in my Scopes field, a token is returned successfully and my bot is able to use the connection.

image

You can combine this with other scopes as needed, but for the sake of experimentation I highly recommend getting the simplest implementation to work first.


Let me know if these instructions work, and if they don't then we'll see if the difference lies in how we've set up our B2C apps.

As a bonus, I should mention that after you get a token you can paste it into https://jwt.ms/ to decode it and see if it recognized your B2C user correctly. Always refresh the page when pasting a new token to make sure it doesn't keep showing you the information from the last token.

silver-stack commented 5 years ago

@v-kydela Firstly, let me say thank you very very much for your assistance on this. With your help I have managed to get this working, however it was partially with your instruction and partially by accident. After a little more investigation I have found out what the issue was... but there is very little documentation on it.

So as stated earlier, my original auth and token endpoints where the following: https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/authorize https://login.microsoftonline.com/tfp/<Tenant ID>/<b2c_Policy>/oauth2/v2.0/token

I then looked at some of the openId connect post requests that you had provided and changed a couple of things as we cannot add parameters (as far as I am aware) in the generic OAuth 2 connection options.

So I decided to copy one of their URL's and paste in my details. My endpoints are now: https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<b2c_Policy>/oauth2/v2.0/authorize https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<b2c_Policy>/oauth2/v2.0/token

I tested them and they worked... but I couldn't understand why this was at first. Then I noticed that I had accidentally omitted the tfp from the URL, which from all my previous links to tutorials and howtos showed that this was a required field if you were using policies. I believe that TFP stands for Trust Framework Policy, however these policies are now known as user flows as far as I can tell.

After some further digging, I found the following setting in my policy under properties: image

As you can see, I actually have the top one selected, which I think is default. If I change this to the bottom one, my log in no longer works. Also to note, I added in my client ID into the scopes as you suggested, and this also has an effect. If I omit it, I get bad request, if I leave it in I get signed in.

This is absolutely great news and I cant wait to get started on our new chatbot.

Once again, thank you, your assistance and details explanations have been much appreciated.

v-kydela commented 5 years ago

That's great news, @silver-stack

I'm glad we could get this resolved