I'm trying to make a sign-in (Angular2 - client and web API 2 - on a server).
I'm receiving a
OPTIONS http://localhost:48604/Token 400 (Bad Request)
followed by
Failed to load http://localhost:48604/Token: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 400.
while other requests don't fail due to CORS issue because I've got CORS enabled globally in WebApiConfig.cs:
Web API:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Configure Web API to use only bearer token authentication. config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); EnableCorsAttribute cors = new EnableCorsAttribute("http://localhost:4200", "*", "*"); config.EnableCors(cors); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } My Startup.Auth.cs :
public partial class Startup { public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; } public static string PublicClientId { get; private set; } // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Configure the application for OAuth based flow PublicClientId = "self"; OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/Token"), Provider = new ApplicationOAuthProvider(PublicClientId), AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AllowInsecureHttp = true }; // Enable the application to use bearer tokens to authenticate users app.UseOAuthBearerTokens(OAuthOptions); // ... Code for third-part logins omitted for brevity ... } } My angular service:
export class AuthService { rootUrl = 'http://localhost:48604'; httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }) }; constructor(private httpClient: HttpClient) { } logIn(loginData): Observable<any> { const data = 'grant_type=password&username=' + loginData.username + '&password=' + loginData.password; return this.httpClient.post(this.rootUrl + '/Token', data, this.httpOptions); } } And as far as I understand after /Token the request should be redirected to api/Account/ExternalLogin but never gets to this controller method.
Then I found an post where they say you need to override MatchEndpoint method in ApplicationOAuthProvider class and I did it:
public override Task MatchEndpoint(OAuthMatchEndpointContext context) { if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS") { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" }); context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization"}); context.RequestCompleted(); return Task.FromResult(0); } return base.MatchEndpoint(context); } in my sign-in component:
this.authService.logIn(loginData).subscribe( (data) => { console.log(data); //sessionStorage.setItem('tokenKey', token); //console.log('sessionStorage.getItem: ' + sessionStorage.getItem('tokenKey')); }, ); now I the response to POST request is 200 OK but still console says:
Failed to load http://localhost:48604/Token: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
then I add another if for a POST method where I also add needed headers:
public override Task MatchEndpoint(OAuthMatchEndpointContext context) { if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS") { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"http://localhost:4200"}); context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] {"authorization"}); context.RequestCompleted(); return Task.FromResult(0); } if (context.IsTokenEndpoint && context.Request.Method == "POST") { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:4200" }); context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization", "Content-Type" }); context.RequestCompleted(); return Task.FromResult(0); } return base.MatchEndpoint(context); } Now the POST method will add headers to response but I get null instead of token.