Reputation: 11227
I have a SPA application that uses MSAL to acquire a token from AAD. Because MSAL works with v2 endpoint and because v2 endpoint does not currently support issuing tokens for custom API's, I'm passing the ID Token to my api and essentially treating my api as the same application. (While this has a smell to it, it does actually work -- at least with Nodejs API).
SPA app
let idToken = Msal.Storage('localStorage').getItem(Msal.Constants.idTokenKey);
this.http.configure(config => {
config.withBaseUrl("http://localhost:3001/")
config.withDefaults({headers: {'Authorization': 'Bearer ' + idToken}})
});
//Call API
this.http.fetch("account")
...
Node.js API
//Using express/passport
var BearerStrategy = require("passport-azure-ad").BearerStrategy;
var options = {
identityMetadata: "https://login.microsoftonline.com/tenantid/.well-known/openid-configuration/",
clientID: "xxxxxxx-xxxx-xxxxxxx-xxxxx",
passReqtoCallback: false,
validateIssuer: true,
issuer: "http://login.microsoftonline.com/{tenantid}/v2.0"
};
app.get("/account",passport.authenticate('oauth-bearer',{session: false}),...
The above all works. Once a user authenticates with the SPA, the token is passed and the call to the Node API works.
I'm now trying to replace the Nodejs API with a .Net WebAPI. I have the following:
Startup.cs
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
//Same ID as used for ClientID in Nodejs
ValidAudience = "xxxxxx-xxxxx-xxxxx-xxxxx",
ValidIssuer = "https://login.microsoftonline.com/{tenantid}/v2.0",
ValidateIssuer = true,
AuthenticationType = "WebApi" //Tried both with and without this
},
Tenant = "{tenantid}" //have tried both id and name
}
)
AccountController.cs
[Authorize]
[Route("account")]
public IHttpActionResult AccountProfile(){
//Get Account information
....
return Ok(profile);
}
However, when I point the SPA app to call the .Net api, I always get Authorization has been denied for this request
.
Is there something I'm missing?
Edit
Incidentally, I've inspected the token that is being used.
The value I'm using for clientID
(Nodejs) and ValidAudience
(.Net) exactly match the aud
claim in the token. The issuer
(Nodejs) and ValidIssuer
(.Net) exactly match the iss
claim in the token. Lastly, the anywhere in my code where I've inserted {tenantid}, the actual value there matches exactly the tid
claim in the token.
Upvotes: 2
Views: 423
Reputation: 18556
We had a similar issue when switching from ADAL to MSAL and got it to work by using a similar approach like this Github project. Specifically take a look at these files:
https://github.com/oktadeveloper/okta-oauth-aspnet-codeflow/blob/master/Api/Startup.cs https://github.com/oktadeveloper/okta-oauth-aspnet-codeflow/blob/master/Api/OpenIdConnectCachingSecurityTokenProvider.cs
Update: Our Startup.cs:
var provider = new OpenIdConnectCachingSecurityTokenProvider(
string.Format(bc2Instace, tenant, policyId));
var jwt = new JwtFormat(clientId, provider);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = jwt,
});
Upvotes: 1