Reputation: 12575
I have a .NET 4.7 Web API project (not .NET CORE).
I am trying to setup authentication with an Azure AD directory, I setup an application in my AD, and I got the client id (application id)
I would like to use the Client Credentials grant type. So I went ahead and retrieved a token via the access token URL https://login.microsoftonline.com/HIDDEN/oauth2/v2.0/token I am passing in the client id, and secret, for this I am using Postman
Now in my project I've implemented the following logic in my web api project:
var clientId = "AZURE APPLICATION ID";
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AllowedAudiences = new List<string> { clientId },
TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidAudience = clientId
}
});
On my controller, I applied the [Authorize] attribute
When calling the API controller endpoint (making sure I am passing in the Authorization header with the value "Bearer MYTOKEN") I get the error returned in Postman:
"Message": "Authorization has been denied for this request."
Is there a way I can dive deeper to figure out what might be wrong?
I don't see anything in my output window in visual studio, are there some events I can hook into why it is failing?
EDIT: Adding more information per Carl:
The token seems to be valid, here are the results from jwt.ms, i even setup an "admin" role via the manifest:
Here is my code, I am not specifying the public signature (not sure how to do that yet), but I've even turned off IssueSignature validation.
This is what my controller looks like:
My fiddler request and response (does having an http endpoint instead of https for local development make a difference?) I don't believe it does:
Upvotes: 2
Views: 2798
Reputation: 114
To your first question of how you can dive deeper, you can create a JwtSecurityTokenHandler
class to capture the exact exception thrown, like so:
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions()
{
AuthenticationMode = AuthenticationMode.Active,
TokenHandler = new SecurityTokenHandler()
});
And the handler class:
public class SecurityTokenHandler : JwtSecurityTokenHandler
{
public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
var principal = base.ValidateToken(token, validationParameters, out validatedToken);
HttpContext.Current.User = principal;
return principal;
}
}
If there are any validation errors, an exception will be thrown by base.ValidateToken
with the specifics of what went wrong (e.g., audience is incorrect, token has expired, etc.).
However, if ValidateToken passes all tests and you are still seeing the error "Authorization has been denied for this request", the problem is almost certainly that the current user was not set to the generated principal. For whatever reason, .NET Framework with JwtBearerAuthenticationOptions
does not correctly handle AuthenticationMode.Active, which is to say, it validates your token, generates a principal, and then does nothing useful with the result.
To fix this, you need this line in the above handler:
HttpContext.Current.User = principal;
It's not great that you have to override JwtSecurityTokenHandler
functionality to fix the problem. But as far as I know, this the only way. Good luck!
Upvotes: 0
Reputation: 9519
You should get a 401 error, which means that the aud
of your token is not your api. The cause of the error is usually that you set the wrong scope
when requesting the token. I used the client credential flow Make a demo for you:
You need to create two applications in Azure ad, one representing the client application and the other representing the api application, and then use the client application to call the Web api application.
First, you need to expose the api of the application representing the web api, you can configure it according to the following process:
Azure portal>App registrations>Expose an API>Add a scope>Add a client application
Next, you need to define the manifest of api applications and 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)
This is the process of defining the manifest.
This is to grant permissions for the client application (You can find your expose api permissions in My APIs.):
Parse the token:
Upvotes: 1
Reputation: 3485
Inspect your access token and ensure the aud
claim value equals the clientId
. Usually the aud
claim will be something like api://clientId which is not what you have setup in your code. If that's the case set it as "api://" + clientId
Upvotes: 2