401 Unauthorized : WWW-Authenticate: Bearer

I've seen similar threads to this issue, but I had no luck solving it. LogIn worked successfuly but when I try to GET data of the user loggedIn in my home page I receive this error 401 Unauthorized the same erroe is showen also in Postman

My startup.cs

 public class Startup
    {
        private string _connectionString=null;
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;

        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            //Inject AppSettings
            services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
            _connectionString = Configuration["secretConnectionstring"];

            //without this it will define for example id to Id 
            services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(options => {
                    var resolver = options.SerializerSettings.ContractResolver;
                    if (resolver != null)
                        (resolver as DefaultContractResolver).NamingStrategy = null;
                });

            services.AddEntityFrameworkNpgsql()
                .AddDbContext<ApiContext>(
                opt => opt.UseNpgsql(_connectionString));

            services.AddEntityFrameworkNpgsql()
                .AddDbContext<AuthentificationContext>(
                options => options.UseNpgsql(_connectionString));
            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<AuthentificationContext>();

            services.Configure<IdentityOptions>(options => {
                options.Password.RequireDigit = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 4;
                });

            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                   .AllowCredentials());
            });

            // Jwt Authentification
           var key = Encoding.UTF8.GetBytes(Configuration["ApplicationSettings:JWT_Secret"].ToString());

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(x=> {
                x.RequireHttpsMetadata = false;
                x.SaveToken = false;
                x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero
                };
            });

            services.AddTransient<dataSeed>();
            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, dataSeed seed)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

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

            // global policy - assign here or on each controller
            app.UseCors("CorsPolicy");


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

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

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

            app.UseAuthentication();



        }
    }
}

UserprofileController

{
    [Route("api/[controller]")]
    [ApiController]
    public class UserProfileController : ControllerBase
    {
        private UserManager<ApplicationUser> _userManager;
        public UserProfileController(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }

        [HttpGet]
        [Authorize]
        //GET : /api/UserProfile
        public async Task<Object> GetUserProfile()
        {
            string userId = User.Claims.First(c => c.Type == "UserID").Value;
            var user = await _userManager.FindByIdAsync(userId);
            return new
            {
                user.fullName,
                user.Email,
                user.UserName
            };
        }
    }
}

UserServices

 headers = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    })
  }
  readonly BaseUrl = 'http://localhost:53847/api';

  constructor(private fb: FormBuilder, private http: HttpClient) { }

  formModel = this.fb.group({
    UserName: ['', Validators.required],
    Email: ['', Validators.email],
    fullName: ['', Validators.required],
    Passwords: this.fb.group({
      Password: ['',[Validators.required, Validators.minLength(4)]],
      ConfirmPassword: ['', Validators.required],
    }, { validator : this.comparePasswords})


  });
  comparePasswords(fb: FormGroup) {

    let confirmPswdCtrl = fb.get('ConfirmPassword');
    //passowrdMismatch
    //confirmPswdCtrl.errors={passowrdMismatch:true}
    if (confirmPswdCtrl.errors == null || 'passowrdMismatch' in confirmPswdCtrl.errors) {
      if (fb.get('Password').value != confirmPswdCtrl.value)
        confirmPswdCtrl.setErrors({ passowrdMismatch: true });
      else
        confirmPswdCtrl.setErrors(null);

    }

  }

  register() {
    var body = {
      UserName: this.formModel.value.UserName,
      Email: this.formModel.value.Email,
      fullName: this.formModel.value.fullName,
      Password: this.formModel.value.Passwords.Password,

    };
    return this.http.post(this.BaseUrl + '/ApplicationUser/Register', body, this.headers);
  }

  login(formData) {
    return this.http.post(this.BaseUrl + '/ApplicationUser/Login', formData, this.headers);

  }
  getUserProfile() {
    var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
    return this.http.get(this.BaseUrl + '/UserProfile', { headers: tokenHeader });
  }
}

ApplicationUserController the PostMethod

  [HttpPost]
        [Route("Login")]
        //POST : /api/ApplicationUser/Login
        public async Task<IActionResult> Login(LoginModel model)
        {
            var user = await _userManager.FindByNameAsync(model.UserName);
            if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
            {
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(new Claim[]
                    {
                        new Claim("UserID",user.Id.ToString())
                    }),
                    Expires = DateTime.UtcNow.AddDays(1),
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
                };
                var tokenHandler = new JwtSecurityTokenHandler();
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                var token = tokenHandler.WriteToken(securityToken);
                return Ok(new { token });
            }
            else
                return BadRequest(new { message = "Username or password is incorrect." });
        }
    }

Help Plz .. Thx

1 answer

  • answered 2019-04-21 08:37 John H

    One problem I see is here:

    var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
    

    When specifying a Bearer token, you need to leave a space between Bearer and the token itself, so that the result looks like this:

    Authorization: <type> <credentials>
    

    In your case, that would translate to:

    Authorization: Bearer token
    

    However, if you look at the code above, you'll see you're actually going to supply it like so:

    Authorization: Bearertoken
    

    which isn't going to work. Therefore, change your code to be:

    var tokenHeader = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('token'), 'Content-Type': 'application/json' });
    // ---------------------------------------------------------^ Notice I've added a space here.