3
votes

Is it possible to secure a Web API in an App Service within Azure, using the built in Authentication/Authorization options and at the same time access it using the OAuth Client Credential Grant flow?

I have an app service being authenticated with Azure AD B2C. In that B2C tenant I have the web app/API registered and authentication working fine for using the web app. I added a scope in the Published Scopes section of that AD B2C app and also added an App ID URI for that scope. Then I created another App (ClientApp) in the tenant to represent another service I want to provide access to the first API. I generated a Secret key for it and also in the API access section added the scope I had created in the other app.

Then in postman I get the token using the next

  • Grant type: Client credentials
  • Access token URL: https://login.microsoftonline.com/mytenantname.onmicrosoft.com/oauth2/v2.0/token (for some reason I have to use login.microsoftonline as the b2clogin domain doesn't work for this)
  • Client ID: The ID that appears in the app registered for the ClientApp
  • Client secret: The secret generated under the ClientApp
  • Scope: the App ID URI I added the the web app registration.

I successfully get the token, but when I try to access the web site using the bearer token with postman, I just get a 401.

3
Yes you can. I am just giving you the overview here. Simply turn on the "Authentication/Authorization" available in Azure App services and configure it with any service provider (e.g. AzureAD) and it will create service principal. Once done go to service principal in Azure AD and grab ClientID/Secret to use them in your client application to get the access token. Use the access token as "Authorize" bearer token to call the WebAPI end point.Imran Arshad
@Imran I edited my question to give more details about my situation. Should I be registering the client app in the Azure AD instead of in the B2C tenant in order to do what you said?Martín La Rosa
You will be registering the client app with tenant that you are using to secure your webapi/webapp , in your case AzureB2C. What sort of client are you using ? Since registering the desktop client is different than web client. find more here docs.microsoft.com/en-us/azure/active-directory-b2c/…. Regarding 401 there are many reasons but most of the times it's because of wrong audience. You can find my answer and turn on logging to know exactly why you are getting 401. stackoverflow.com/a/53591038/1041953Imran Arshad
The client app is another app service. What logs do you mean I should look? The web api logs won't contain anything because the app never gets hit because I can't pass through the authentication.Martín La Rosa
For the audience, what I did was entering as clientId the id of the app registered in B2C as the client app, and as the secret a secret generated within that app. But also tried using the web app id of the main web api app also with a secret generated for it, and it also doesn't work.Martín La Rosa

3 Answers

0
votes

It is not supported to use client_credentials flow against AAD B2C application registrations. Therefore you have to instead create an App Registration through the normal Azure AD Blade instead.
https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-apps#current-limitations

Then the App Service must accept tokens from 2 different authorities, which App Services cannot do with EasyAuth (Authentication enabled at the App Service configuration menu).

You would instead need to use a library that can accept tokens from multiple authorities. There is an example here:
Use multiple JWT Bearer Authentication

0
votes

I've spent hours to find a proper solution.

This solution: https://stackoverflow.com/a/48657826/11721142 doesn't work with mine B2C setup (is almost ideal :) ). I had to change original:

"additionalLoginParams": [
  "response_type=code id_token",
  "resource=<AAD-app-id-for-your-webapi-webapp>"
]

To:

"additionalLoginParams": [
  "scope="scope=https://xxx.onmicrosoft.com/{Guid}/all+openid+offline_access""
]

Where

https://xxx.onmicrosoft.com/{Guid}/all is your scope identifier defined in B2C API permisions

Then... finally I can call {frontend-app-domain}/.auth/login/aad and... see: access-token, id-token and refresh-token after {frontend-app-domain}/.auth/me

You can also provide required scopes like that: {frontend-app-domain}/.auth/login/aad?scope=<see scopes above>

-1
votes

Not sure if I understand it correctly, but it seems you are using a URL as scope. It works if you set the scope to the application id of the app service (you can find an enterprise application with the name of your app service in azure AD) instead of using the URL. (format: /.default)

I am still trying to figure out if it is possible to use the URL as scope...