Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OWIN token authentication 400 Bad Request on OPTIONS from browser

I am using token authentication for small project based on this article: http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/

Everything seems to work fine except one thing: OWIN based token authentication doesn't allow OPTIONS request on /token endpoint. Web API returns 400 Bad Request and whole browser app stops sending POST request to obtain token.

I have all CORS enabled in application as in sample project. Below some code that might be relevant:

public class Startup
    {
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }

        public void Configuration(IAppBuilder app)
        {
            AreaRegistration.RegisterAllAreas();
            UnityConfig.RegisterComponents();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            HttpConfiguration config = new HttpConfiguration();

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            ConfigureOAuth(app);

            WebApiConfig.Register(config);

            app.UseWebApi(config);

            Database.SetInitializer(new ApplicationContext.Initializer());
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            //use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
                Provider = new SimpleAuthorizationServerProvider(),
                RefreshTokenProvider = new SimpleRefreshTokenProvider()
            };

            // Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(OAuthBearerOptions);
        }
    }

Below is my login function from javascript (I am using angularjs for that purpose)

var _login = function (loginData) {

        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;

        data = data + "&client_id=" + ngAuthSettings.clientId;

        var deferred = $q.defer();

        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {

        localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName, refreshToken: response.refresh_token, useRefreshTokens: true });
        _authentication.isAuth = true;
        _authentication.userName = loginData.userName;
        _authentication.useRefreshTokens = loginData.useRefreshTokens;

        deferred.resolve(response);

        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });

        return deferred.promise;
    };

    var _logOut = function () {

        localStorageService.remove('authorizationData');

        _authentication.isAuth = false;
        _authentication.userName = "";
        _authentication.useRefreshTokens = false;

    };
like image 443
VsMaX Avatar asked Oct 28 '14 17:10

VsMaX


People also ask

What is Owin authentication?

OWIN (Open Web Interface for . NET) is a standard for an interface between . NET Web applications and Web servers. It is a community-owned open-source project. The OAuth authorization framework enables a third-party application to obtain limited access to a HTTP service.

What is bearer token authentication in Web API?

Bearer token. A particular type of access token, with the property that anyone can use the token. In other words, a client doesn't need a cryptographic key or other secret to use a bearer token. For that reason, bearer tokens should only be used over a HTTPS, and should have relatively short expiration times.


2 Answers

I've lost some time on this problem today. Finally i think i've found a solution.

Override method inside your OAuthAuthorizationServerProvider:

public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
    if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization" });
        context.RequestCompleted();
        return Task.FromResult(0);
    }

    return base.MatchEndpoint(context);
}

This appears to do three necessary things:

  • Force auth server to respond to OPTIONS request with 200 (OK) HTTP status,
  • Allow request to come from anywhere by setting Access-Control-Allow-Origin
  • Allows Authorization header to be set on subsequent requests by setting Access-Control-Allow-Headers

After those steps angular finally behaves correctly when requesting token endpoint with OPTIONS method. OK status is returned and it repeats request with POST method to get full token data.

like image 158
knr Avatar answered Oct 15 '22 06:10

knr


Override this method inside your OAuthAuthorizationServerProvider:

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }
like image 42
Prakash D Modi Avatar answered Oct 15 '22 06:10

Prakash D Modi