Microsoft-authentication-library-for-js: Custom dotnetcore web api authentication Azure AD App configuration

Created on 1 Nov 2019  路  31Comments  路  Source: AzureAD/microsoft-authentication-library-for-js

I'm submitting a...


[x] Other... Please describe: Question

How to authenticate (and perhaps even authorize) against a custom dotnetcore web api?
Or, more specifically, what scope to use and how to set this up in the Azure AD?

My API looks like this: https://gist.github.com/eirikb/74aad1eb90a06408e752bb12e60769d4
With these important parts:

_Startup.cs_
```C#
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc();
}


_appsettings.json_
```C#
{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "********.onmicrosoft.com",
    "ClientId": "********-****-****-****-************",
    "TenantId": "********-****-****-****-************"
  }

I've been looking around, but haven't found any good guides on how to set this up with msal. I don't understand how/where to set up scope in Azure portal (Azure AD App registrations), and/or how to reflect this in the web api.

Should be noted I have been able to create scopes under _Expose an API_ then use _Add a scope_, and I have been able to use msal to get accessToken for these scopes, but when I use it as a bearer against my app I get 4** error.

My SPA will not be hosted in proximity to the API, I expect a bearer token should work regardless for API location/url.

question

All 31 comments

@anomepani Thanks for the answer.
I've been looking at the samples (as well as other samples on the same GH Org), but I'm still not quite sure what to do.

The example you provided has a description that seems to fit me really well, and it probably is just what I want, but when I look at the details I get confused. Here are some differences in my setup: I have an API, not a webapp, I don't use cookies (MSAL use JWT), I'm not going to delegate calls to other APIs such as Graph, and I'm not doing B2C.

@eirikb for what purpose you are creating WebAPI(Server) and Who(_Client React, Angular App or mobile App_) will use this Web API or Consume Web API?

If Client App Login with MSAL and Call your Web API with the generated token then the authentication validation should be implemented on your Web API Side.

For this type of scenario, this example might be helpful to you https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2/tree/master/2.%20Web%20API%20now%20calls%20Microsoft%20Graph

I found a very interesting video by @jmprieur , that demonstrates and explains the video of the above code as well.
Here it is https://www.youtube.com/watch?v=5qZRzwjKNJ4

I managed to solve it by using this guide: https://mobilefirstcloudfirst.net/2019/08/adding-azure-active-directory-authentication-connect-angular-app-asp-net-core-web-api-using-msal/
The trick was to use api:// in front of ClientId in appsettings.json. I didn't have to do all the things in the guide, e.g., I used the same app, and I never granted any permissions or added any client app - I don't see any reason to not just use the same app if possible.

If anyone want a demo I can throw my whole project (including simple msal auth client) on GitHub.

The issue can now be closed - but I still don't know how to use scopes in my API, that would be nice to know before closing.

It would be great if you share your project on github so Other dev can help you to resolve exact issue which you have.

@eirikb Check your repository I have a pull request for basic jwt configuration and CORS Issue.
It will help you little bit about getting started.

@anomepani Sorry I don't understand, my example works just fine, it does what it should do.

I thought you are having difficulty to call secure web api from spa.
So I have updated your web api solution with authorize attributes which understand jwt authorization

Ok. The demo works fine, no change needed. Did you try to run it? It should "just work".

Anyway, when I said the issue can be closed, and mentioned scopes, what I meant was how to use different scopes. E.g., how to create say a scope for Read (read only) and FullConctrol (Admin). I don't need this yet, but would be nice to know.
I have some ideas, which involves multiple Azure AD Apps, but some hints in the issue before closing was what I hoped for.

Yes SPA demo working but how to validate on web api server side not implemented.
For your query msft identity team will help you.

What do you mean that validation is not implemented server side? Are you saying that my implementation is not secure?
The client must be authenticated with msal, against the Azure AD App. I understand that the specific scope is probably not checked, but does that matter? And I can't see that being done in your PR either.

@eirikb : you need to check that the token your Web API received is for your web api
This article (and the following) explains it all
https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-app-configuration#code-initialization

@jmprieur Are you answering about how to handle multiple scopes now, or security issues in my solution?
If I understand the setup correctly my solution will ensure that the user is authenticated against the given Azure AD App, and this app is only used for the API, so wouldn't that be sufficient?
I tested sending other tokens from other ClientIds and they fail, isn't this the point of having ClientId in appsettings.json?

@eirikb : mostly the security issues in the Web API (I advise you to read the Scenario: Protected web API articles, you'll see that this won't be sufficient as your API as it is will accept any token, really (unless I'm wrong you don't test the audience for your token, nor the issuer).

@eirikb : if you want to handle multiple scopes, just register them in the app registration (the article tells you how to do), and then have several controller actions one with each scope.

@jmprieur If you are correct, and this renders my API not secure, then this is a big problem. You probably saw the article I linked to earlier does exactly the same as me, and I've seen others online as well.
If this approach, which is the simplest/cleanest approach, is flawed then are these other people introducing security issues?

@eirikb : yes, this is a problem with the current ASP.NET Core templates. We are working on introducing new Visual Studio / .NET Core templates to have APIs which are secure by default. No ETA, though.

The recommendation is to leverage the https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2 sample for Web APIs (and read the article about protected APIs)

I think I see what you mean; because the app is multi tenant any other tenant can install it and then call my API. All they need is the ClientId, which can be retrieved from the client-side code.

If the Azure AD App was set for organization only, then it would be secure - because then I verify that the user is authenticated user from my organization, which is basically all i require?

@eirikb : yes, single tenant would be safe, except if you were sent a fake token by any issuer that is not Azure AD; but you would also want to check scopes/roles.

Feel free to close the issue if you think we answered.

@jmprieur What do you mean by

except if you were sent a fake token by any issuer that is not Azure AD

Is it possible to create a fake token? Doesn't AddAzureADBearer verify the JWT is issued from Microsoft?


For others reading this; when using a single tenant msal must be configured like this:

const msal = new UserAgentApplication({
  auth: {
    clientId,
    authority: `https://login.microsoftonline.com/${tenant}`
  }
});

It's either that, or do some audience validation in the API.

It depends on the value of ValidateIssuer. for single tenant, we are good.

This is good. Thank you for the answer.
It might be a good idea to drop a comment on the article I linked to - the article is not wrong, but it should be mentioned that the API is actually not locked down at all, it's open for anyone able to get their hands on the non-secret ClientId.

@jmprieur Yes

@eirikb : thanks. I've added a comment in the blog post
thanks again for raising this concern.

Just a heads up for anyone stumbling upon this issue; the solution of using single tenant will still (obviously) allow for guest users to use your API.
I believe guests include users such as DevOps Stakeholders and SharePoint guest invitations - any user you find in your Azure AD.

This is probably not desirable, at least not for our in-house API.
@jmprieur sorry to bother you again with this, but would it be a good solution if I were to use Roles?
I've already tried implementing this, and it seems to work, but I need some verification of what I have done:

@eirikb : I'm not completely sure, but i believe using groups requires a non-free SKU of Azure AD. Are you using a free one?
@kalyankrishna1 would you know?

@jmprieur Azure AD Premium P1. But that might be a problem for others. Nice to know.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Calamari picture Calamari  路  3Comments

atvoid picture atvoid  路  3Comments

exequeryphil picture exequeryphil  路  3Comments

ed-ilyin picture ed-ilyin  路  4Comments

Anees-Raja picture Anees-Raja  路  3Comments