0

I know this is a very common problem I faced myself in the past, but I was always able to deal with it enabling cors in DotNet Core Api startup.cs, but what's going on this time seems a little bit more weird.

My Angular 8 app does a post request first at login (this request inlcudes no httpHeader because no token is present yet) and it works (I have previously enabled cors for it to work).

After I get a token I store it in localstorage for later use, but to my big surprise when api controller has [Authorize] tag and the post includes header with token, then request fails with cors error and it doesn't even hit server method.

Error in vscode console:

Access to XMLHttpRequest at 'http://localhost:55909/api/manifest/add' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. [http://localhost:4200/] 

Angular 8 post request that works (login) and I got return (token):

login(username: string, password: string) { return this.http.post<any>(`${environment.apiUrl}/api/login/authenticate`, { username, password }) .pipe(map(user => { let oUser = new User(); oUser.username = user['name']; oUser.token = user['token']; localStorage.setItem('currentUser', JSON.stringify(oUser)); let token = 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token; this.currentUserSubject.next(user); return user; })); } 

Authenticate method in login controller that works:

[HttpPost] [Route("authenticate")] [EnableCors("Cors")] public ActionResult Authenticate(LoginRequest login) { if (!validCredentials(login)) return userUnauthorized(); TokenGenerator.settings = settings; var token = TokenGenerator.GenerateTokenJwt(login.Username); user.Token = token; return new JsonResult(new User { Name = user.Name, Token = user.Token }); } 

Angular 8 post request that fails:

this.headers = new HttpHeaders({ 'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token, 'Content-Type': 'application/json' }); return this.http.post<any>(`${environment.apiUrl}/api/manifest/add`, { name, surname, seat, flight }, { headers: this.headers }) .pipe(map(result => { return result; })); 

Angular 8 post request that also fails:

this.headers = new HttpHeaders({ 'Authorization': 'Bearer ' + JSON.parse(localStorage.getItem('currentUser')).token, 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Headers': 'Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name', 'Access-Control-Allow-Methods': 'POST,GET,PUT,PATCH,DELETE,OPTIONS' }); return this.http.post<any>(`${environment.apiUrl}/api/manifest/add`, { name, surname, seat, flight }, { headers: this.headers }) .pipe(map(result => { return result; })); 

DotNet Core Api controller method that is not even get hit:

[Authorize] [HttpPost] [Route("add")] [EnableCors("Cors")] public ActionResult Add(Passenger passenger) { Response response = repository.addPassenger(passenger); return new JsonResult(response); } 

startup.cs "ConfigureServices" method where I enable cors:

public void ConfigureServices(IServiceCollection services) { services.AddHttpContextAccessor(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // Add functionality to inject IOptions<T> services.AddOptions(); // Add our Config object so it can be injected services.Configure<AppSettings>(Configuration.GetSection("AppSettings")); services.AddCors(o => o.AddPolicy("Cors", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowCredentials() .AllowAnyHeader(); })); //Add repository to scope services.AddScoped<UserRepository>(); services.AddScoped<PassengerRepository>(); //sql connection and context (with crypted pass) var connection = getConnectionString(); services.AddDbContext<Context>(options => options.UseSqlServer(connection)); } 

The weird thing is if I remove [Authorize] directive from "Add" method then it works, but I obviously lose token validation.

Help, please :)

1 Answer 1

1

After hours of struggling my head I figured out:

First I forgot to use

app.UseAuthentication(); 

in Configure in startup.cs

Second, instead of just

[Authorize] 

I have to use

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 

to define a default validation schema.

Third I didn't know I have to install

"AspNet.Security.OAuth.Validation" 

to implement token validation. Did it through Nuget manager.

Now it works, so I answer my own question, and I hope this will help anyone else with the same problem.

Edit 1: To avoid "401 Unauthorized" error.

With all mentioned steps above I got controller method to start being hit, but the response was always being 401 (even with a valid token), so I had to add the next piece of code in startup to make it to validate correctly:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("thisisasupersecuresecretkey")), RequireSignedTokens = false, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "http://localhost:55909", ValidAudience = "http://localhost:55909" }; }); 

I know there are obviously many different ways to achieve this, but this combination of pieces of code worked in my case for a basic use of case.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.