B2C app scopes not going to API app - azure-web-app-service

I have separate UI web app from the API web app. Both registered as applications in B2C. I've enabled Azure App Service Authentication / Authorization (easy auth) on the UI web app, and configured the API web app to use JwtBearer middleware to authenticate calls to API.
This seems to work, but I have trouble getting scopes through to the API web app. I have published the scopes in the API app, and configured the UI app to have access to these scopes.
I've tried different login URL options, e.g., https://myUIapp.azurewebsites.net/.auth/login/aad?p=b2c_1a_mysigninpolicy&scope=openid+https://myb2ctenant.onmicrosoft.com/api/company.read&post_login_redirect_uri=/app
and ensured that the API apps "App ID URI" (in B2C app settings) is indeed "api", while the scope name is company.read. Still after successful authentication, when going to /.auth/me, I do not see the scope, I do see other claims just fine.
Where should I start looking into pointers on this?
UPDATE
I've determined how I end up in this situation, but it is still unclear why:
User authenticates starting with URL such as: https://login.microsoftonline.com/mydevb2c.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_signin&client_id=UIAPP_GUID&nonce=defaultNonce&redirect_uri=https%3A%2F%2FUIAPP.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&scope=openid%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.write%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.read&response_type=id_token%20token&prompt=login
After successful authentication, user is redirected to https://UIAPP.azurewebsites.net/.auth/login/aad/callback, as defined, BUT is immediately redirected back to authentication system with default scope set "openid+profile+email", i.e. URL such as https://login.microsoftonline.com/mydevb2c.onmicrosoft.com/oauth2/v2.0/authorize?response_type=id_token&redirect_uri=https%3A%2F%2FUIAPP.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&client_id=UIAPP_GUID&scope=openid+profile+email&response_mode=form_post&p=b2c_1a_signinsuomifi&nonce=somenonce&state=redir%3D%252Fapp
If I take the access_token from the first callback to /.auth/login/aad/callback it contains the requested scopes, but second authentication callback obviously doesn't as it requests default scope set.
Do I perhaps need to start the easy auth login process via .auth/login/aad in order for it to accept the callback as well?
UPDATE 2
Yes, need to start the process via .auth/login/aad: when using login URL such as https://myUIapp.azurewebsites.net/.auth/login/aad?p=B2C_1A_signin&redirect_uri=https%3A%2F%2FmyUIapp.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&scope=openid%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.write%20https%3A%2F%2Fmydevb2c.onmicrosoft.com%2Fapi%2Fcompany.read&response_type=id_token%20token&prompt=login&post_login_redirect_uri=/app removes the second authentication redirect.
The question now is, why do I only see the id_token in .auth/me and not the access_token that is clearly returned to the .auth/login/aad/callback? And ultimately: how come using the access_token as Bearer token, I still cannot query the easy auth secured API, but get error You do not have permission to view this directory or page.? I have followed steps in Azure client app accessing Azure api secured by AD.
If I switch off easy auth, and use the JwtBearer middleware in my API, it works fine.

Related

Authenticating with oAuth token from service principal, produces a "the audience is invalid" error

I'm authenticating with a service principal that was setup by another developer. I'm trying to authenticate against an internally developed API. The ASP is working when the other developer uses the SDK to authenticate. But when I try with Postman, I'm getting a 401 with this error.
The issue is that I don't really know which resource to use. I believe the client ID, secret, and scope is correct. But I can't seem to find any info on the type of resource to use. Is there any way to determine this for an internally developed API? I've used a ton of publicly available ones. Just as testing, as I can't find any info. And leaving it blank does not work.
Assuming you have two applications created in azure ad app registration, one representing the client application and the other representing the api application, (or in app registration you must have selected the required client application) and then you must be using the client application to call the Web api application.
NOTE: When you call web API , make sure you are sending Access token (not Id token)
you track the token you get in jwt.io .
Azure AD audience must match the “aud” claim when.
The Audience must equal the AppId or client id set for the application.
Check iss value of token in jwt.io and see the version of login url. If it is v2 set manifest json in the app registration for the API to 2, as it may be by default be 2.
"accessTokenAcceptedVersion": 2
In the app registration if your exposed api is something like : api://xxxx-xxx-xxx ,then the client id in appsettings.json of your app must be the same.
Note:Client id may be configured differently according to application.
If above doesn't work try client ID : instead of api://
You may need to grant application permissions to your client applications (this is the role permissions you define yourself, you can find it in My APIs when you add permissions).Then you need to click the admin consent button to grant administrator consent for this permission.
Here I exposed scope >> api://xxx-xxx-xxx/access_as_user. Make sure to use the same scope configured in portal is included in application configuration. The scope should include the exposing resource's identifier (the Application ID URI) in the code too.
Here Ex: scopes: "api://xxxx-xxx-xxxx/access_as_user "
In postman Set Authorization header to refer a global variable 'Bearer {{bearerToken}}' and add the authorization data to Request Headers,
If you are using postman call back uri , uncheck the authorize using browser for callbackurl in postman configuration.(see enable-azure-ad-authentication| csharpcorner )

How can I use azure ad access token which is got from SPA to protect backend api?

I want to use azure AD as authentication.
If user who is in certain organization logged in from SPA, and give access token to backend, then I want to permit access from SPA.
So, I want to check if token passed from SPA is valid or not.
How can I do this?, Or Can I do this?
I want to build backend server with node.js app, and deploy backend app to app service or Azure Container Registry.
I think bearerStrategy would work.
Ref https://github.com/AzureAD/passport-azure-ad
BearerStrategy uses Bearer Token protocol to protect web resource/api.
It works in the following manner: User sends a request to the
protected web api which contains an access_token in either the
authorization header or body. Passport extracts and validates the
access_token, and propagates the claims in access_token to the verify
callback and let the framework finish the remaining authentication
procedure. On successful authentication, passport adds the user
information to req.user and passes it to the next middleware, which is
usually the business logic of the web resource/api. In case of error,
passport sends back an unauthorized response.
In the past, there was an ADAL version for node apps. I don't know if it's still valid or not, but here are useful links:
https://medium.com/#liangjunjiang/verify-and-decode-azure-activity-directory-token-bc72cf7010bc
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios

Refresh token denied and empty response for viewing tokens in token store

I have deployed an azure app to azure app service. It has no frontend part, simply an API app that does some http calls.
I have configured the Authentication/Authorization section to log anonymous requests using Azure AD.
I have registered the app in AD and connected everything together.
Here is the problem:
Upon first sign in, everything works great, I sign in and the jwt token is sent to my app and I can parse it.
However if I am already signed in and go to my app again a jwt token is not sent. However doing a GET request to /.auth/me simply returns [].
If I send a request to /.auth/refresh I get a 403 forbidden.
A bit stuck on how to proceed here. Thanks.
What is the status of your Action to take when request is not authenticated? Is it Allow anonymous or Sign-in with Azure AD?
If it is the former (allow anonymous), what you observe is expected behavior.
If it the latter - it is not expected.
When you set to "Allow anonymous" you instruct to not do anything if request is not authenticated. So, nothing happens, and you do not see any token. If you configure to "Login with ...", you will be automatically redirected if you are not authenticated.
UPDATE
Can you define "If I am already signed in.."? Also, if you configured to not allow anonymous request, every request hitting your application code will be authenticated. The app service authentication module takes care of intercepting unauthenticated calls and redirects them. Additionally /.auth/me endpoint will redirect to sign-in all unauthenticated calls, but /.auth/refresh will not.
You may also want to enable token store, which is enabled by default. The option is located directly under the list with authentication providers.
You can find more information about authentication and authorization in Azure App Service here:
https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to - check out the sections access user claims, retrieve tokens in app code and refresh identity provider token

AAD Refresh Tokens with Ionic 2 PWA

I have an Ionic 2 app that works as a native app and as a progressive web app hosted on an Azure Web Site (which is not the same site as my API App Service Site). On the mobile side, I can get refresh tokens successfully by using the mobile SDK's login method and the making the REST call. However on the web side (PWA), I can't use the SDK to login because InAppBrowser won't work because login.microsoftonline.com sets X-Frame-Options to DENY. Therefore, I redirect the browser to /.auth/login/aad?session_mode=token&post_login_redirect_url= with a redirect URL coming back to my PWA index page. That sends me the token back via #token which I am able to parse and use to successfully authenticate to my back-end API.
What doesn't work for me is calling /.auth/refresh. That always gives me the error:
The refresh request issued by sid... failed because no refresh tokens
were found in the token store.
The API App is configured to return an access token for graph.microsoft.com and I can see the refresh token in an initial call to /.auth/me. I can also login directly via a browser session using /.auth/login/aad and no parameters. There I can call /.auth/me and /.auth/refresh successfully
So what I am trying to figure out is how to make this work in the browser. I need the user to get redirected back to my app so I specify the post_login_redirect_url parameter. With that the user gets logged in successfully and redirected to my app. However, that is when the call to /.auth/refresh fails with the error above. I am hoping this is just a matter of not passing the right parameters to the login endpoint but I am not sure.

Is it possible to anonymously call API App and it automatically redirect the browser to AD Login page?

During the recent Microsoft Cloud roadshow in London, something that came out of one of the talks on App Service was using AAD B2C for authentication.
It is possible currently to add Azure AD as an authentication for an API App:
Calling this API app from a browser based web app with no authorization header results in a 302 redirect immediately followed by a 401 response.
It was mentioned at the cloud event that it would be possible to call an API app anonymously from a web app, and have the azure App service handle the redirection to the AAD login page, get the token on successful login and then pass the call on to the API app and return the data.
However, I am struggling to see how this can be achieved without any responsibility on the calling web app to handle the redirect. Normally you would handle a 401 response from an API by obtaining a bearer token via AAD on the client side and sending it through as the authorisation header with the api request.
I have been through numerous examples on the Azure site and others and all of them are handling the logon/obtaining the token in the client web app.
Is this even possible?
UPDATE I just realized (as pointed out by #Darrel-Miller that you don't really want to allow the user to put the credentials in.
The only thing that is still unclear to me, is where do you want to provide the credentials for AAD?, What is it exactly what you would like to accomplish.
Even more, why would you use AAD if there no user interaction at all.
If all that you want is a secure connection you can just use the standard application key for the web api without enabling AAD. And its as pretty straight forward to just add the MS_ApplicationKey to your header and you are good to go.
As you described in your comment you have a webclient that tries to do the requests and gets the 302, that is why my original answer wast that you would use ADAL. But now that I get deeper into what you want probably what you want to use is KurveJS :
https://github.com/MicrosoftDX/kurvejs
And it has the AAD app model v2 with Active Directoy B2C.
This makes it easy to add third party identity providers such as Facebook and signup/signin/profile edit experiences using AD B2C policies
You can read more about it here:
https://github.com/MicrosoftDX/kurvejs/blob/master/docs/B2C/intro.md
Do you mean this??
https://msdn.microsoft.com/en-us/magazine/dn463788.aspx
Just use ADAL nuget package to handle the call...
You can read this from the post:
As soon as the execution hits the call to AcquireToken, you’ll get the authentication dialog shown in Figure 8. ADAL takes care of contacting the right endpoint and rendering the authentication experience provided by the server in a pop-up dialog without requiring you to write any UI code.
I hope this works for you!

Resources