I thought my goal was simple enough. I have a client that makes calls to a Web API (registered in an Azure B2C tenant) to receive an access token. So far so good. When I use this access token to call a Web API method that is secured with the [Authorize] tag, I only get back an 401 Unauthorized error.
I’m using ASP.NET Core 3.1.
1. Web Api – My method to acquire the token:
IPublicClientApplication app = PublicClientApplicationBuilder.Create(_clientId)
.WithB2CAuthority(_authority)
.Build();
result = await app.AcquireTokenByUsernamePassword(_scopes, _username, _password)
.ExecuteAsync();
return Ok(result.AccessToken);
This returns a token and when I enter it in jwt.io it looks okay, with the right username and scopes, but at the bottom it says "Invalid Signature". This could be the problem, but someone also had a similar issue and claimed that it worked for him anyway. It makes me uncomfortable and maybe someone can tell me reasons why the signature could be invalid or what this means exactly.
2. Local Client – sending my requests:
HttpRequestMessage request = new HttpRequestMessage()
{
Method = method,
RequestUri = new Uri(_httpClient.BaseAddress + requestUri),
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
return await _httpClient.SendAsync(request);
3. Web Api – Startup.cs
service configuration:
Here I tried so many things that I couldn’t say which one worked best, because none of them seemed to work. I thought this version looked promising:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureB2C")
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
4. appsettings.json
I also tried different settings here and I didn’t know what to use for my ROPC policy, so I entered it into "SignUpSignInPolicyId" which probably is a problem too:
"AzureB2C": {
"Instance": "https://[tenant].b2clogin.com/",
"Domain": "[domain name]",
"TenantId": "[tenantId]",
"ClientId": "[clientId]",
"SignUpSignInPolicyId": "[ropc policy name]",
"B2cExtensionAppClientId": "[client id of b2cextensionapp]",
"Scopes": "[scopeurl]"
}
Any help with this would be extremely appreciated since I’m going a little crazy with this. I’m pretty new to Azure, authorization and Web APIs in general, but I researched a lot over the last weeks and I still don’t understand why this is not working, especially since I’m getting back an access token for the right user.
Thank you!
2
Answers
I found the problem. The token I received with "return Ok(result.AccessToken)" contained "" characters because it's the value part of a json. I trimmed the characters and now it works. And to answer the question in your head, yes, I'm feeling pretty stupid right now :P
Any parts can go wrong, let’s try some simple things first.
Isolate the problem. On the B2C Azure portal, use the Run user flow tool for the SignInSignUpPolicy you have used. You can get a token from that tool. Then use that JWT, and send it to your protected API. If it works, then the issue is in your get token endpoint. If not working, then your configuration is wrong.
I also noticed that you don’t have the "ApplicationIdUri" in your appsettings. See reference.
Let me know how it goes and we can try other things.