locked
CORS policy blockade ERROR - 'http://localhost:33428/token' from origin 'http://localhost:4200' has been blocked by CORS policy. RRS feed

  • Question

  • User-215451226 posted

    I am trying to do login/authentication from my Angular8 APP by making request to backend C# WebAPI. Facing the problem --

    Access to XMLHttpRequest at 'http://localhost:33428/token' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    http://localhost:33428 being address where my API is being hosted. Now, let me give some code,

    1.  claims method -

    [EnableCors(origins: "http://localhost:4200", headers: "*", methods: "*")]
        public class AccountController : ApiController
        {
    
            [HttpGet]
            [Route("api/Account/GetUserClaims")]
            public AccountModel GetUserClaims()
            {
                var identityClaims = (ClaimsIdentity)User.Identity;
                IEnumerable<Claim> claims = identityClaims.Claims;
                AccountModel model = new AccountModel()
                {
                    UserName = identityClaims.FindFirst("Username").Value,
                    Email = identityClaims.FindFirst("Email").Value,
                    FirstName = identityClaims.FindFirst("FirstName").Value,
                    LastName = identityClaims.FindFirst("LastName").Value,
                    LoggedOn = identityClaims.FindFirst("LoggedOn").Value
                };
                return model;
            }
        }

    2.  my startup which contains the 'token' endpoint defn_

    public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
    
                app.UseCors(CorsOptions.AllowAll);
    
                OAuthAuthorizationServerOptions option = new OAuthAuthorizationServerOptions
                {
                    TokenEndpointPath = new PathString("/token"),
                    Provider = new ApplicationOAuthProvider(),
                    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(80),
                    AllowInsecureHttp = true
                };
                app.UseOAuthAuthorizationServer(option);
                app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
            }
        }

    3. webapiConfig 

    public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API configuration and services
    
                config.EnableCors(new EnableCorsAttribute("http://localhost:4200", headers: "*", methods: "*"));
    
                // Web API routes
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.Filters.Add(new AuthorizeAttribute());
    
                var json = config.Formatters.JsonFormatter;
                json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
                config.Formatters.Remove(config.Formatters.XmlFormatter);
            }
        }

    4. ApplicationOAuthProvider provider class

    public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
        {
    
            public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                context.Validated();
            }
    
            public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            {
                var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
                var manager = new UserManager<ApplicationUser>(userStore);
                var user = await manager.FindAsync(context.UserName, context.Password);
                if (user != null)
                {
                    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                    identity.AddClaim(new Claim("Username", user.UserName));
                    identity.AddClaim(new Claim("Email", user.Email));
                    identity.AddClaim(new Claim("FirstName", user.FirstName));
                    identity.AddClaim(new Claim("LastName", user.LastName));
                    identity.AddClaim(new Claim("LoggedOn", DateTime.Now.ToString()));
                    var userRoles = manager.GetRoles(user.Id);
                    foreach (string roleName in userRoles)
                    {
                        identity.AddClaim(new Claim(ClaimTypes.Role, roleName));
                    }
                    var additionalData = new AuthenticationProperties(new Dictionary<string, string>{
                        {
                            "role", Newtonsoft.Json.JsonConvert.SerializeObject(userRoles)
                        }
                    });
                    var token = new AuthenticationTicket(identity, additionalData);
                    context.Validated(token);
                }
                else
                    return;
            }
    
            public override Task TokenEndpoint(OAuthTokenEndpointContext context)
            {
                foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
                {
                    context.AdditionalResponseParameters.Add(property.Key, property.Value);
                }
    
                return Task.FromResult<object>(null);
            }
        }

    5. from my angular app the request I make -->

    OnSubmit(userName, password) {
        this.userService.userAuthentication(userName, password).subscribe((data: any) => {
          console.log('login success');
          localStorage.setItem('userToken', data.access_token);
          localStorage.setItem('userRoles', data.role);
          this.router.navigate(['/home']);
        },
          (err: HttpErrorResponse) => {
            console.log('login error');
            this.isLoginError = true;
          });
      }

    6. In the angular service method

    userAuthentication(userName, password) {
        var data = "username=" + userName + "&password=" + password + "&grant_type=password";
        var reqHeader = new HttpHeaders({ 'Content-Type': 'application/x-www-urlencoded', 'No-Auth': 'True' });
        return this.http.post(this.rootUrl + '/token', data, { headers: reqHeader });
      }
    
    
    
    
    where rootUrl --> 'http://localhost:33428'; as you would expect.

    SO what's the issue with CORS here? I 'seem' to have configured most of the CORS specifications in the correct appr. places. Then? I tried sending this same authentication request through POSTMAN also, with username and password to authenticate and it gives a 404 Error Message.
    What grief? What modification is required, fellows can you tell me?

    Do you need some more code blocks to see, to locate the source of my error? Would be happy to help.

    Look forward to your able guidance,

    Thanks much,

    Wednesday, July 10, 2019 5:27 PM

Answers

  • User-215451226 posted

    Hi All,

    I solved this one myself, After considerable amount of digging through the Microsoft. DOCs. See, my '/token' endpoint was defined in the Startup.cs file and that was not being hit in the first place when I launched my API project. Why? Because in a project created with 4.7.2 framework you need to add separately, additional code so that the OWIN Startup class is identified in the first place.  See this --> https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-startup-class-detection

    In my case, even though I was adding my Startup class manually to the project, it was not being recognized/identified in the first place. I had another option; to downgrade project framework to 4.5, or 4.5.1, so that the Startup.cs gets added AUTOMATICALLY. In either case, now as I launch my API project, the Configuration method in that class gets hit and subsequently all authentication and /token logic also. Everything works fine for me now.

    Took some time, but I discovered this answer myself.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, August 6, 2019 2:34 PM

All replies

  • User475983607 posted

    Use the browser's dev tool (F12) to view the actual response.  Most likely it is an error caused by an exception.  Errors are not CORS compliant by default.   Also try setting a break point and run your code through the Visual Studio debugger as it is not clear where you are calling the token end point.  Has this code ever worked?  Did you copy the resource own grant validation from a tutorial?

    Wednesday, July 10, 2019 5:53 PM
  • User-215451226 posted

    Did you copy the resource own grant validation from a tutorial?



    yes, that's what I did. this one --> https://github.com/CodAffection/Angular-5---Role-Based-Authorization-with-Web-API
    Follow the code in the WebAPI portion.

    Upon clicking authenticate, it is supposed to hit the 'GetUserClaims' method. But it doesn't. That's the thing I am inspecting WHY. I used breakpoint and it did not hit there. Let me see step by step, if this is due to some exception in some other step. I am not sure it would be able to locate it. Nevertheless.

    Let me know, if you observe something wrong/incorrect.

    Wednesday, July 10, 2019 6:40 PM
  • User475983607 posted

    PGChoudhury

    mgebhard

    Did you copy the resource own grant validation from a tutorial?



    yes, that's what I did. this one --> https://github.com/CodAffection/Angular-5---Role-Based-Authorization-with-Web-API
    Follow the code in the WebAPI portion.

    Upon clicking authenticate, it is supposed to hit the 'GetUserClaims' method. But it doesn't. That's the thing I am inspecting WHY. I used breakpoint and it did not hit there. Let me see step by step, if this is due to some exception in some other step. I am not sure it would be able to locate it. Nevertheless.

    Let me know, if you observe something wrong/incorrect.

    You do not understand how the code works.  You are implementing the resource owner grant and should authenticate with the /token endpoint.  The /token endpoint should return the token which contains the user claims.  Your client app, Angular, persists the token and pass the token when requesting a secured URL.

    Did you use Dev Tools to view the response from the server?  Use the network trace not the console which has the CORS error.  I bet there's an error which should help troubleshoot.

    Lastly, are you sure the github project works?

    Wednesday, July 10, 2019 7:44 PM
  • User-215451226 posted

    Yes, I ran the sample and it works as expected, just fine. No glitches there.

    Maybe I am not sure how the code works. Could you just provide me a briefed up jist of the process starting from -- clicking the login button to all the subsequent requests and calls? Hopefully I can find the region that is creating difficulty. I want to cross check this with my understanding of it, whatever I wrote earlier.
    The most basic question I have is - why is http://localhost:33428/token not being hit.

    Why?

    Thursday, July 11, 2019 3:45 PM
  • User-215451226 posted

    @mgebhard this is a screenshot, my network performance after I click the LOGIN button --

    [<blockquote class="imgur-embed-pub" lang="en" data-id="a/jWybtIr"><a href="//imgur.com/a/jWybtIr"></a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>].
    Take a look -- [https://imgur.com/a/jWybtIr]


    if that helps,

    Thursday, July 11, 2019 4:29 PM
  • User283571144 posted

    Hi PGChoudhury,

    According to your description, I have created a test demo on my side according to the github sample. It works well. I could access the token path.

    I suggest you could make sure the path you have used is right or the web api application is started completely.

    Best Regards,

    Brando

    Friday, July 12, 2019 6:14 AM
  • User-215451226 posted

    Hi @BrandoZWZ,

    there's definitely something wrong with my configuration. Cuz this is what I get.
    [https://imgur.com/a/JBaVEQ6]

    I am not getting the clean, [error:unsupported grant type] response in the preview tab.

    What could be wrong? I can share my whole API proj_ itself [it is not so big in any case] so you can directly see and play with the nut bolts and possibly locate my error. Could there be something missing in my global.asax.cs?

    Currently I got this -

    protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
            }

    Please advise,

    Friday, July 12, 2019 3:54 PM
  • User-215451226 posted

    Hi again,

    If you study that sample code and its authentication mechanism, the first breakpoint that is hit is in the class ApplicationOAuthProvider and the method GrantResourceOwnerCredentials. Subsequently goes to the TokenEndpoint method and finally the GetUserClaims which returns the entire user related data model from DB.
    SO what I am wondering is in my case, why the breakpoint on GrantResourceOwnerCredentials method is not being hit.
    The /token endpoint is not so much my concern right now.


    Any ideas, people in the house,

    Saturday, July 13, 2019 4:12 PM
  • User283571144 posted

    Hi PGChoudhury,

    Your error code is 404, that means the url is wrong. The request doesn't send to your web API application.

    I suggest you could check the RouteConfig and WebApiConfig code to make sure the "/token" path is right. 

    Best Regards,

    Brando

    Monday, July 15, 2019 6:17 AM
  • User-215451226 posted

    Hi All,

    I solved this one myself, After considerable amount of digging through the Microsoft. DOCs. See, my '/token' endpoint was defined in the Startup.cs file and that was not being hit in the first place when I launched my API project. Why? Because in a project created with 4.7.2 framework you need to add separately, additional code so that the OWIN Startup class is identified in the first place.  See this --> https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-startup-class-detection

    In my case, even though I was adding my Startup class manually to the project, it was not being recognized/identified in the first place. I had another option; to downgrade project framework to 4.5, or 4.5.1, so that the Startup.cs gets added AUTOMATICALLY. In either case, now as I launch my API project, the Configuration method in that class gets hit and subsequently all authentication and /token logic also. Everything works fine for me now.

    Took some time, but I discovered this answer myself.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, August 6, 2019 2:34 PM