Enable CORS for Web Api 2 and OWIN token authentication - asp.net-web-api

I have an ASP.NET MVC 5 webproject (localhost:81) that calls functions from my WebApi 2 project (localhost:82) using Knockoutjs, to make the communication between the two projects I enable CORS. Everything works so far until I tried to implement OWIN token authentication to the WebApi.
To use the /token endpoint on the WebApi, I also need to enable CORS on the endpoint but after hours of trying and searching for solutions it is still now working and the api/token still results in:
XMLHttpRequest cannot load http://localhost:82/token. No 'Access-Control-Allow-Origin' header is present on the requested resource.
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
TokenConfig.ConfigureOAuth(app);
...
}
TokenConfig
public static void ConfigureOAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
AuthorizationProvider
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
var appUserManager = context.OwinContext.GetUserManager<AppUserManager>();
IdentityUser user = await appUserManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
... claims
}
IdentityConfig
public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
// Tried to enable it again without success.
//context.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});
var manager = new AppUserManager(new UserStore<AppUser>(context.Get<ApplicationDbContect>()));
...
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<AppUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
EDIT:
1. Important note is that opening the endpoint directly (localhost:82/token) works.
2. Calling the Api (localhost:82/api/..) from the webproject also works, so the CORS is enabled for WebApi.

I know your issue was solved inside comments, but I believe is important to understand what was causing it and how to resolve this entire class of problems.
Looking at your code I can see you are setting the Access-Control-Allow-Origin header more than once for the Token endpoint:
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
And inside GrantResourceOwnerCredentials method:
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
This, looking at the CORS specifications, is itself an issue because:
If the response includes zero or more than one Access-Control-Allow-Origin header values, return fail and terminate this algorithm.
In your scenario, the framework is setting this header two times, and understanding how CORS must be implemented, this will result in the header removed in certain circumstances (possibly client-related).
This is also confirmed by the following question answer: Duplicate Access-Control-Allow-Origin: * causing COR error?
For this reason moving the call to app.UseCors after the call to ConfigureOAuth allows your CORS header to be set only once (because the owin pipeline is interrupted at the OAuth middleware, and never reaches the Microsoft CORS middleware for the Token endpoint) and makes your Ajax call working.
For a better and global solution you may try to put again app.UseCors before the OAuth middleware call, and remove the second Access-Control-Allow-Origin insertion inside GrantResourceOwnerCredentials.

Follow below steps and you will have your API working:
Remove any code like config.EnableCors(), [EnableCors(header:"*"....)] from your API.
Go to startup.cs and add below line
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
before
ConfigureAuth(app);
Uou will also need to install Microsoft.owin.cors package to use this functionality

Solving the problem without using app.UseCors()
I had the same problem. I used a Vue.Js client with axois to access my REST-API with cross-corps. On my Owin-Api-Server I was not able to add Microsoft.Owin.Cors nuget due to version conflicts with other 3rd party components. So I couldn't use app.UseCors() method but I solved it by using the middleware pipeline.
private IDisposable _webServer = null;
public void Start(ClientCredentials credentials)
{
...
_webServer = WebApp.Start(BaseAddress, (x) => Configuration(x));
...
}
public void Configuration(IAppBuilder app)
{
...
// added middleware insted of app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.Use<MyOwinMiddleware>();
app.UseWebApi(config);
...
}
public class MyOwinMiddleware : OwinMiddleware
{
public MyOwinMiddleware(OwinMiddleware next) :
base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
var request = context.Request;
var response = context.Response;
response.OnSendingHeaders(state =>
{
var resp = (IOwinResponse)state;
// without this headers -> client apps will be blocked to consume data from this api
if (!resp.Headers.ContainsKey("Access-Control-Allow-Origin"))
resp.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
if (!resp.Headers.ContainsKey("Access-Control-Allow-Headers"))
resp.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });
if (!resp.Headers.ContainsKey("Access-Control-Allow-Methods"))
resp.Headers.Add("Access-Control-Allow-Methods", new[] { "*" });
// by default owin is blocking options not from same origin with MethodNotAllowed
if (resp.StatusCode == (int)HttpStatusCode.MethodNotAllowed &&
HttpMethod.Options == new HttpMethod(request.Method))
{
resp.StatusCode = (int)HttpStatusCode.OK;
resp.ReasonPhrase = HttpStatusCode.OK.ToString();
}
}, response);
await Next.Invoke(context);
}
}
So I created my own middleware and manipulated the response. GET calls only needed the Access-Control-Allow headers whereas for OPTIONS calls I also needed to manipulate the StatusCode because axois.post() is calling first with OPTIONS-method before sending the POST. If OPTIONS return StatusCode 405, the POST will never be sent.
This solved my problem. Maybe this can help somebody too.

Related

HttpContext.Current is null in OpenId Connect OWIN middleware on SecurityTokenValidated

I'm working on a bug related to an OpenId Connect middleware (OWIN) in an ASP.NET Web Forms application which authenticates to Azure AD. I'm completely new to OWIN and OpenID, and did not write this code so bear with me.
The solution was tested and seemingly worked just fine, but once it hit production we saw multiple null reference exceptions, due to HttpContex.Current being null when the SecurityTokenValidated notification middleware was called.
The issue appear to happen roughly 30%-40% of the time the user tried to log in to production. We were initially not able to reproduce the issue locally, but we eventually found out we could reproduce 100% of the time by setting network speed in Chrome to Fast/Slow 3G speed (interestingly enough).
This is our code in the Startup.cs class to configure the Middleware:
[assembly: OwinStartup(typeof(Namespace.Startup))]
namespace Namespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var openIdConnectProvider = OpenIdConnectProviderDAO.GetOpenIdConnectProviders().Single(x => x.ClientId == "ClientIdHere");
app.Use((context, next) =>
{
var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
return next();
});
app.UseStageMarker(PipelineStage.MapHandler);
app.SetDefaultSignInAsAuthenticationType(OpenIdConnectAuthenticationDefaults.AuthenticationType);
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = openIdConnectProvider.ClientId,
Authority = openIdConnectProvider.Authority,
RedirectUri = ConfigurationHelper.GetAppSetting("applicationRoot").ToLower(),
AuthenticationType = openIdConnectProvider.Key,
AuthenticationMode = AuthenticationMode.Passive,
ResponseType = OpenIdConnectResponseType.IdToken,
Scope = OpenIdConnectScope.Email,
TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = openIdConnectProvider.ValidIssuer,
ValidateIssuer = true,
ValidAudience = openIdConnectProvider.ClientId,
ValidateAudience = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = OnSecurityTokenValidated,
AuthenticationFailed = OnAuthenticationFailed
}
});
}
private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> arg)
{
// This is null when connection speed is set to Slow/Fast 3G
var context = HttpContext.Current;
return Task.FromResult(0);
}
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
context.HandleResponse();
context.Response.Redirect("Login.aspx");
return Task.FromResult(0);
}
}
}
We need to access the HttpContext.Current in order to access the Session in the SecurityTokenValidated middleware. So we added the middleware as suggested in these posts:
Can OWIN middleware use the http session?
HttpContext.Current.Session is null + OWIN
This seemingly worked great, until the issues started popping up in production.
I've tried to use various combinations of UseStageMarker in various PipelinesStages (Authenticate, PostAcquireState etc), but none of them has worked.
Any help will be greatly appreciated!
Having the same issue, ran into this link. I found a solution to my problem on github.
Basically, add an empty Session_OnStart() method on Global.asax
Hope it helps others running into this problem.

When using an API route, return Http Response 401 instead of redirect to login page when not authorised

I'm building an ASP.NET Core 2.0 website using MVC and WebAPI to provide access to a series of microservices. Where a WebAPI controller requires a user to be authenticated and authorised (using the Authorize attribute), any unauthorised or not-logged in user gets the response back as the entire HTML for the MVC login page.
When unauthorised users access the API, I would like to return the HTTP status code 401 and its associated error message in the response, instead of an entire HTML page.
I've looked at a few existing questions and noticed that they either refer to ASP.NET MVC (such as SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi) which is no good for ASP.NET Core 2.0. Or they are using a hackaround for Core 1.x, which just doesn't seem right (ASP.Net core MVC6 Redirect to Login when not authorised).
Has a proper solution been implemented in Core 2.0 that anyone is aware of? If not, any ideas how it could be implemented properly?
For reference, there's part of a controller as an example:
[Authorize]
[ApiVersion("1.0")]
[Produces("application/json")]
[Route("api/V{ver:apiVersion}/Organisation")]
public class OrganisationController : Controller
{
...
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
return await _organisationService.GetAllSubdomains();
}
...
}
And the configurations within Statup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
// Add API version control
services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.ErrorResponses = new DefaultErrorResponseProvider();
});
// Add and configure MVC services.
services.AddMvc()
.AddJsonOptions(setupAction =>
{
// Configure the contract resolver that is used when serializing .NET objects to JSON and vice versa.
setupAction.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseStatusCodePagesWithRedirects("/error/index?errorCode={0}");
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
...
}
There is an easy way to suppress redirect to Login page for unathorized requests. Just add following call of ConfigureApplicationCookie extension method in your ConfigureServices:
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
return Task.CompletedTask;
};
});
Or if you need custom error message in response body:
services.ConfigureApplicationCookie(options =>
{
options.Events.OnRedirectToLogin = async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await context.Response.WriteAsync("Some custom error message if required");
};
});
As far as you're using redirects to custom error pages for error codes (UseStatusCodePagesWithRedirects() call in Configure method), you should add filter for 401 error. To achieve this, remove call to UseStatusCodePagesWithRedirects and use UseStatusCodePages extension method with skip of redirect for Unauthorized code:
//app.UseStatusCodePagesWithRedirects("/error/index?errorCode={0}");
app.UseStatusCodePages(context =>
{
if (context.HttpContext.Response.StatusCode != (int)HttpStatusCode.Unauthorized)
{
var location = string.Format(CultureInfo.InvariantCulture, "/error/index?errorCode={0}", context.HttpContext.Response.StatusCode);
context.HttpContext.Response.Redirect(location);
}
return Task.CompletedTask;
});
If you're using JWT for authentication with an ASP.NET Core 2 API; you can configure the unauthorized response when you're configuring the services for Authentication & JWT:
services.AddAuthentication( JwtBearerDefaults.AuthenticationScheme )
.AddJwtBearer(options => options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = c =>
{
c.NoResult();
c.Response.StatusCode = 401;
c.Response.ContentType = "text/plain";
return c.Response.WriteAsync("There was an issue authorizing you.");
}
});

Web app and web api authentication in same application

I have a web app MVC,using auth0 owin regular web app cookie based authentication.
This web app also has webapis which is used internally in the application. However i have a requirement to call this webapis from outside the application. So i created a restclient and tried to implement jwtbearerauthentication in application (but cookie based on authentication still in place).
Now when i call the webapi from other application it validates the bearer token gives no error however it redirects to login page due to cookie based authentication.
startup file:
public partial class Startup
{
private IPlatform platform;
public void ConfigureAuth(IAppBuilder app, IPlatform p, IContainer container)
{
platform = p;
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
ExpireTimeSpan = System.TimeSpan.FromDays(2),
SlidingExpiration = true
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
var provider = new Auth0.Owin.Auth0AuthenticationProvider
{
OnReturnEndpoint = (context) =>
{
// xsrf validation
if (context.Request.Query["state"] != null && context.Request.Query["state"].Contains("xsrf="))
{
var state = HttpUtility.ParseQueryString(context.Request.Query["state"]);
AntiForgery.Validate(context.Request.Cookies["__RequestVerificationToken"], state["xsrf"]);
}
return System.Threading.Tasks.Task.FromResult(0);
},
OnAuthenticated = (context) =>
{
var identity = context.Identity;
//Add claims
var authenticationManager = container.Resolve<IAuthenticationManager>();
authenticationManager.AddClaims(identity);
if (context.Request.Query["state"] != null)
{
authenticationManager.AddReturnUrlInClaims(identity, context.Request.Query["state"]);
}
return System.Threading.Tasks.Task.FromResult(0);
}
};
var issuer = "https://" + ConfigurationManager.AppSettings["auth0:Domain"] + "/";
var audience = ConfigurationManager.AppSettings["auth0:ClientId"];
var secret = TextEncodings.Base64.Encode(TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["auth0:ClientSecret"]));
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
app.UseAuth0Authentication(
clientId: platform.ServerRole.GetConfigurationSettingValue("auth0:ClientId"),
clientSecret: platform.ServerRole.GetConfigurationSettingValue("auth0:ClientSecret"),
domain: platform.ServerRole.GetConfigurationSettingValue("auth0:Domain"),
provider: provider);
}
}
webapiconfig file:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional});
config.Filters.Add(new AuthorizeAttribute());
ODataConfig.Setup(config);
var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];
config.MessageHandlers.Add(new JsonWebTokenValidationHandler()
{
Audience = clientID,
SymmetricKey = clientSecret
});
}
Currently creating the jwt token from below code and posting using postman in header just to check if it works.. but redirects to login page.
string token = JWT.Encode(payload, secretKey, JwsAlgorithm.HS256);
I suspect what's happening is that your call to the API has a bearer token which fails validation (or there is no Authorize token at all), your API controller has an Authorize attribute, which, since there is no valid ClaimsPrincipal on the call throws 401. Auth0AuthenticationProvider picks that and assumes the call was to UI so redirects for user authentication. You may want to add an override in the Oauth0Provider to trap OnRedirectToIdP (or something like that), inspect the request and if it is to API, abot further handling and return Unauthorized.
Remove any [Authorize] from your API and see whether it works then. Also make sure your startup does not require Authorize for all controllers.
You may want to remove the authn part of your code (cookie and Oauth2Provider) and see whether you are getting to the API then.
A few years late i know, but i recently came across the same requirement in a project, and found this sample put together by a dev at Auth0.
https://github.com/auth0-samples/aspnet-core-mvc-plus-webapi
The example in the link allows for cookie authentication OR token authentication for the API endpoints.
The key takeaway for me was using attributes on your routes to tell the pipline what authentication mechanism to use. In my case i wanted cookie authentication for the UI and token authentication for the endpoints. i had no requirement to use both for any single area of the project.
controller:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet]
[Route("api")]
public string TestAuth()
{
return "All good " + this.User.FindFirst(ClaimTypes.NameIdentifier).Value + ". You only get this message if you are authenticated.";
}

CORS error on requesting OWIN token

I need to implement OWIN authorization from web api server. Below is my startup class.
[assembly: OwinStartup(typeof(SpaServerSide.MyStartUp))]
namespace SpaServerSide
{
public class MyStartUp
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
app.Map("/signalr", map =>
{
map.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var hubConfig = new Microsoft.AspNet.SignalR.HubConfiguration { };
map.RunSignalR(hubConfig);
});
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/#")
});
OAuthAuthorizationServerOptions OAuthOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
Provider = new SpaServerSide.Shared.OAuthTokenServer()
};
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
}
}
Then, I implement the OAuthAuthorizationServerProvider as the following :
public class OAuthTokenServer : OAuthAuthorizationServerProvider
{
public ASPIdentityUserManager cusUserManager;
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
var user = await cusUserManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "Username and password do not match.");
return;
}
var identity = await cusUserManager.CreateIdentityAsync(user, context.Options.AuthenticationType);
context.Validated(identity);
}
}
After that, I have hosted the web server on http://localhost:5587 and client web site on http://localhost. When I tried to request the token using Angular JS, the browser threw me an CORS error. The message is as follows :
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:5587/Token. (Reason: CORS
header 'Access-Control-Allow-Origin' missing).
Please suggest me anything I would have missed.
Move the line:
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
at the beginning of your Configuration() method.
You have to configure CORS middleware before oauth middleware. And before signalr middleware if you need it.
Try this
Enable browser setting for allowing cross origin access
IE: http://www.webdavsystem.com/ajax/programming/cross_origin_requests
Firefox: How to enable CORS on Firefox?
Chrome: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en
I think u need enable CORS in your server side. U can refer to this http://enable-cors.org/server.html . Click link based on your server.
Hope that help u. :)

ASP.NET WEB API 2 OWIN Authentication unsuported grant_Type

Hi I am trying to set up OAuth bearrer token authentication in my ASP.NET Web API 2 project.
I have two project one will be the WEB API Project and the other a SPA project.
Here is what I have done so far:
I have created the OWIN Startup class:
[assembly: OwinStartup(typeof(CodeArt.WebApi.App_Start.Startup))]
namespace CodeArt.WebApi.App_Start
{
public class Startup
{
static Startup()
{
PublicClientId = "self";
UserManagerFactory = () => new UserManager<UserModel>(new UserStore<UserModel>());
OAuthOptions = new OAuthAuthorizationServerOptions {
TokenEndpointPath = new PathString("/Token"),
Provider = new OAuthAuthorizatonServer(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static Func<UserManager<UserModel>> UserManagerFactory { get; set; }
public static string PublicClientId { get; private set; }
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalBearer);
app.UseOAuthBearerTokens(OAuthOptions);
}
}
I have configured Web API to use only bearer token authentication:
private static void ConfigureBearerTokenAuthentication(HttpConfiguration config)
{
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(Startup.OAuthOptions.AuthenticationType));
}
I have configured WEB API to support CORS:
private static void ConfigureCrossOriginResourseSharing(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
}
I have created the OAuthAuthorizationServerProvider class.From this class I only managed to make my code call this method:
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
if(context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
The if condition inside of it always gets executed.
On my spa project I have the following:
This is my viewModel:
var vm = {
grant_type: "password",
userName: ko.observable(),
password: ko.observable()
};
When the login button gets clicked I call this function:
var http = {
post:function(url, data) {
return $.ajax({
url: url,
data: data,
type: 'POST',
contentType: 'application/json',
dataType: 'jsonp'
});
}
}
function loginClick() {
var model = ko.mapping.toJS(vm.loginModel);
var rez = $.param(model);
http.post("http://localhost:3439/Token", rez)
.done(function (data) {
console.log(data);
})
.fail(function(eror, stuff, otherstuff) {
console.log(eror);
console.log(stuff);
console.log(otherstuff);
});
}
My first attempt I have set the post calls dataType to json and I got this errors:
OPTIONS ...:3439/Token 400 (Bad Request) jquery.js:7845
OPTIONS ...:3439/Token No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin
'...:3304' is therefore not allowed access.
jquery.js:7845
XMLHttpRequest cannot load ...3439/Token. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin '...3304' is therefore not allowed
access.
The 3 dots represent http://localhost.
The second time arround I set it datatype to jsonp and I got back an error that stated unsupported "unsupported_grant_type".
Both calls make it to ValidateClientAuthentication that I mentioned above but they are both sent back as a failed request.
Now I am guessing that the problem is more related to how I am sending data instead of the grand_type because the SPA template in Visual Studion set's the grant type to grant_type: "password" like I did.
Also I have read that I have to serialize the data not send it in json in order for this to work here is the exact json serialized data that get's sent:
"grant_type=password&userName=aleczandru&password=happynewYear&moduleId=models%2FappPostModels%2FloginModel"
The model id property get's set to all my object in my SPA template by Durandal Framework.
Can anyone tell me what I am doing wrong I have been trying to figure this out for the last two days?
Add the following line of code to GrantResourceOwnerCredentials, which will add the header to the response.
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
for more information refer to:
web-api-2-0-cors-and-individual-account-identity
Like Robin Karlsson said, you should use:
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
in your Startup configuration.
And make sure it's the only cors statement (don't mix them) and the first statement in your Startup.

Resources