Reputation: 750
My SharePoint Add-in runs this JavaScript to get a message from my Greeting API:
async function getGreeting() {
// https://www.youtube.com/watch?v=P3vkerr1nW8
var client = new Msal.UserAgentApplication(config);
var request = {
scopes: ['user.read'],
prompt: 'select_account'
};
let loginResponse = await client.loginPopup(request);
let tokenResponse = await client.acquireTokenSilent(request);
var theToken = tokenResponse.accessToken;
// https://zinoui.com/blog/jquery-ajax-headers
$.ajax({
url: 'https://localhost:44316/Greeting',
type: 'GET',
headers: {
'Authorization': 'Bearer ' + theToken
},
timeout: 600000,
success: function (theGreeting) { alert(theGreeting); },
error: function () { alert('Error'); }
});
}
My ASP.NET Core 3.1 controller has this code:
namespace SharePointTestAPI.Controllers
{
// https://www.yogihosting.com/aspnet-core-enable-cors/
[Authorize]
[EnableCors("SharePointOnline")]
[ApiController]
[Route("[controller]")]
public class GreetingController : ControllerBase
{
[HttpGet]
public String Get()
{
return "Great Value Canned Salmon is Rich in Omega-3 and Vitamin D!!!";
}
}
}
If I comment out the [Authorize] attribute, an alert box pops up and shows the expected message about Walmart Salmon. Unfortunately, if I put the [Authorize] attribute back in, I see this error in a response header:
WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid"
The tokens I get back from acquireTokenSilent looks good on both the client and the server. In both cases, they decode fine at https://jwt.ms/ , so I don't know why MicrosoftIdentityWebApiAuthentication seems to be complaining that the tokens are invalid.
My ConfigureServices function in Startup.cs looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
// https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0
// https://www.yogihosting.com/aspnet-core-enable-cors/
options.AddPolicy(
"SharePointOnline",
builder =>
{
builder.WithOrigins(
"https://myTestTenant-3b3547c0f805ae.sharepoint.com"
).AllowAnyHeader().AllowAnyMethod();
}
);
}
);
services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd");
services.AddControllers();
}
Here is my sanitized appsettings.json:
{
/*
The following identity settings need to be configured
before the project can be successfully executed.
For more info see https://aka.ms/dotnet-template-ms-identity-platform
*/
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "myTenantName.onmicrosoft.com",
"TenantId": "[someGUID]",
"ClientId": "api://[someOtherGUID]",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Can someone please help me understand why MicrosoftIdentityWebApiAuthentication seems to think my authentication token is corrupt?
Upvotes: 4
Views: 1495
Reputation: 750
I kept getting "Invalid Token Signature" Error because I was erroneously getting back an Access Token instead of an Id Token... I needed to change the following line in my getGreeting Function from:
var theToken = tokenResponse.accessToken;
to
var theToken = tokenResponse.idToken.rawIdToken;
After that was fixed, I kept getting "Invalid Audience" Errors which were unrelated to the signature error. To get rid of that, I think I had to create an appRoles scope in Azure AD via the "Expose an API" Section:
After creating that appRoles scope, I also changed the scopes request in my getGreeting function from:
scopes: ['user.read'],
to
scopes: ['api://[myClientId]/appRoles'],
I think these additional changes allowed my SharePoint Add-in to get a Token from my API instead of Microsoft Graph. Once I made the above two changes, my API returned the expected greeting to my SharePoint Add-in.
My new getGreeting function is shown below:
async function getGreeting() {
// https://www.youtube.com/watch?v=P3vkerr1nW8
var client = new Msal.UserAgentApplication(config);
var request = {
scopes: ['api://[myClientId]/appRoles'],
prompt: 'select_account'
};
let loginResponse = await client.loginPopup(request);
let tokenResponse = await client.acquireTokenSilent(request);
var theToken = tokenResponse.idToken.rawIdToken;
// https://zinoui.com/blog/jquery-ajax-headers
$.ajax({
url: 'https://localhost:44316/Greeting',
type: 'GET',
headers: {
'Authorization': 'Bearer ' + theToken
},
timeout: 600000,
success: function (theGreeting) { alert(theGreeting); },
error: function () { alert('Error'); }
});
}
Lastly, I changed my ClientId in the appsettings.json file of my Web API from:
"ClientId": "api://[someOtherGUID]",
back to (without the leading api://):
"ClientId": "[someOtherGUID]",
My final appsettings.json is shown here:
{
/*
The following identity settings need to be configured
before the project can be successfully executed.
For more info see https://aka.ms/dotnet-template-ms-identity-platform
*/
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "myTenantName.onmicrosoft.com",
"TenantId": "[someGUID]",
"ClientId": "[someOtherGUID]",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Upvotes: 3