I have a spa that is sending a get request to a web api.
When I dont have the authorize attribute, I am able to get the values (of course!). Adding the authorize attribute always returns a 401 response.
After scratching my head on this for 2 weeks straight, I feel like only SO gods can help.
I have the following questions:
- What am I doing wrong?
- Is there a better way to do this?
- How can I log the incoming token on the server side? (Just so I can validate it at jwt.io)
Assuming my keys, tenant, client(id) etc are properly set up,
My code on spa is like this:
'use strict';
angular.module('todoApp')
.controller('homeCtrl', ['$scope', '$http', 'adalAuthenticationService', '$location', function ($scope, $http, adalService, $location) {
$scope.apiData = [];
$scope.login = function () {
adalService.login().then(function () {
console.log('yay');
});
};
$scope.logout = function () {
adalService.logOut();
};
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
$scope.getData = function () {
// #1: Set up ADAL
var authContext = new AuthenticationContext({
clientId: 'myclientid',
postLogoutRedirectUri: window.location
});
var user = authContext.getCachedUser();
if (user) {
console.log(user);
console.log('Signed in as: ' + user.userName);
} else {
console.log('Not signed in');
}
var tokenStored;
authContext.acquireToken(
'https://graph.windows.net',
function (error, token) {
// TODO: Handle error obtaining access token
if (error || !token) {
console.log('Error no token');
return;
}
console.log("token is:" + token);
tokenStored = token;
$http.get('https://localhost:44301/api/values', {
headers: { 'Authorization': 'Bearer ' + tokenStored, }
}).then(function (response) {
$scope.apiData = response.data;
console.log(response);
alert('Data recieved');
});
});
};
}]);
My Api Startup.cs looks like this:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//ToDo: Implement Logger Factory
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
// Shows UseCors with CorsPolicyBuilder.
// global policy - assign here or on each controller
app.UseCors("CorsPolicy");
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
// TokenValidationParameters = tokenValidationParameters
});
app.UseMvc();
}
My controller method looks like this
[Route("api/values")]
[Authorize]
[EnableCors("CorsPolicy")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IActionResult Get()
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
var results = _interconnectCodesRepository.GetCodes();
return Ok(results);
}
else
{
return BadRequest();
}
}
}
}
Any suggestions or hints will be much appreciated.
Thanks
To get the token from .net core web API project, we can add
AuthenticationFailed
event like below:The token you were acquiring using the resrouce
https://graph.windows.net
in the code is for the Azure Graph REST instead of your API. There is no need to acquire the token manually in the client for the SPA application. The ADAL library will acquire and append the token based on the resource automatically. We just only need to init which endpoints we want to request. Here is the js code for your reference:For the web API side, we need to specify the the
Authority
andAudience
or other parameters as you wanted( refer the first piece of code).On the Azure side, we need to register two web applications. One presents the client and the other presents the resource protected by Azure AD. For example, in my test scenario, I registered ToDoSPA and ToGoAPI and grant the permission as figure below:
And to make the ToDoSPA application integrate with Azure AD with implicit flow for the SPA app, we also need to modify its manifest to set the
oauth2AllowImplicitFlow
totrue
.In addition, here are some helpful links about protecting the web API with Azure AD:
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore
https://github.com/Azure-Samples/active-directory-angularjs-singlepageapp-dotnet-webapi
https://github.com/AzureAD/azure-activedirectory-library-for-js
Update( custom AudienceValidator)