4

I'm working on a brand new ASP.NET Core 2.1 SPA app with React/Redux front end. I've implemented jwt authentication which gets its token from Azure AD B2C.

When I analyze the network tab for my API call to the backend, I see that token is placed in the header -- see below:

enter image description here

Here's the code for my fetch call:

import { fetchOptionsGet, fetchOptionsPost, parseJSON } from '../../utils/fetch/fetch-options';

export const getData = () => {

    return (dispatch) => fetch("/api/accounts/test", fetchOptionsGet())
        .then((response) => {

            if (response.ok) {

                parseJSON(response)
                    .then(result => {
                        // Do something here...
                    })
            }
        })
};

Here's my fetch options:

export const fetchOptionsGet = () => {

    const token = authentication.getAccessToken();
    debugger
    return {
        method: 'GET',
        mode: 'cors',
        headers: {
            "Content-Type": "application/json",
            "Authentication": "Bearer " + token
        }
    }
}

Notice the debugger in the above code to make sure I'm getting the token which confirms I have the token -- not to mention it's my network call as well.

Here's the ConfigureServices() method in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
        services.AddAuthentication(options => {
             options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
         })
         .AddJwtBearer(jwtOptions => {
         jwtOptions.Authority = $"https://login.microsoftonline.com/tfp/{Configuration["AzureAdB2C:Tenant"]}/{Configuration["AzureAdB2C:Policy"]}/v2.0/";
         jwtOptions.Audience = Configuration["AzureAdB2C:ClientId"];
         jwtOptions.Events = new JwtBearerEvents
         {
              OnAuthenticationFailed = AuthenticationFailed
         };
     });

     services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

     // In production, the React files will be served from this directory
     services.AddSpaStaticFiles(configuration =>
     {
         configuration.RootPath = "ClientApp/build";
     });
}

Here's the Configure() method in Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
       app.UseDeveloperExceptionPage();
    }
    else
    {
       app.UseExceptionHandler("/Error");
       app.UseHsts();
    }

    app.UseHttpsRedirection();

    ScopeRead = Configuration["AzureAdB2C:ScopeRead"];
    app.UseAuthentication();

    app.UseStaticFiles();
    app.UseSpaStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
    });

    app.UseSpa(spa =>
    {
        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment())
        {
           spa.UseReactDevelopmentServer(npmScript: "start");
        }
     });
}

Here's the API controller:

[Produces("application/json")]
[Route("api/[controller]")]
[Authorize]
public class AccountsController : Controller
{
    [HttpGet("test")]
    public async Task<IActionResult> Test()
    {
        // Do something here...
    }
}

I put a break point right at the beginning of my Test() API method but I'm not hitting it. Without the [Authorize] attribute, I'm able to hit the Test() API method and get my data. So, something in the pipeline is blocking the call before I even hit the API method.

I also tried specifying the authorization scheme in my API controller with the following but that didn't make any difference. Still getting a 401 error.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Any idea where I'm making a mistake here?

5
  • There’s probably something useful in the output -> debug window. See anything? Commented May 18, 2018 at 23:52
  • Have you put a break point on your OnAuthenticationFailed handler? Commented May 18, 2018 at 23:56
  • 2
    The header name should be Authorization. Commented May 19, 2018 at 1:33
  • 1
    @Brad You have the eyes of an eagle my friend!!!! You got it. That was the problem! Now it works nicely. Could you please post your response as an answer so that I can accept it. I'd like you to get credit for your help! I can't thank you enough buddy! I've wasted so much time on this. Thanks again!!! Commented May 19, 2018 at 1:41
  • In my case, [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] makes all difference. Thanks, now its working! Commented Mar 25, 2021 at 16:03

1 Answer 1

3

The header name should be Authorization.

export const fetchOptionsGet = () => {

    const token = authentication.getAccessToken();
    debugger
    return {
        method: 'GET',
        mode: 'cors',
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer " + token //<--
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.