2

I am using .Net ASP Web API V2 with Angular 1 and Auth0.

After initial login through Auth0 I am getting the following error:

XMLHttpRequest cannot load localhost:3001/profile. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:62379' is therefore not allowed access. The response had HTTP status code 500.

If I refresh I no longer get the error. If I clear the browser data I get the error again but get success after a refresh.

I have CORS enabled in the API config with the required NUGET packages.

I have tried the following solutions because I thought this was a pre-flight issue:

1) Handling the SELECT verb on the controller and globally by intercepting the request. http://www.jefclaes.be/2012/09/supporting-options-verb-in-aspnet-web.html

2) Adding the select verb as one of the accepted verbs on the controller method.

3) Various answers I have found on here for changing the request. ** I can not share links my rep is too low.

etc.

4) Using a specific origin instead of *

The Controller:

    [Route("profile")]
    [EnableCors(origins: "*", headers: "*", methods: "OPTIONS")]
    public HttpResponseMessage Options()
    {
        var resp = new HttpResponseMessage(HttpStatusCode.OK);
        resp.Headers.Add("Access-Control-Allow-Origin", "*");
        resp.Headers.Add("Access-Control-Allow-Methods", "*");
        return resp;
    }


    [Route("profile")]
    [EnableCors(origins: "*", headers: "*", methods: "POST")]
    [HttpPost]
    public object Post([FromBody]dynamic data)
    {
        string email = null;
        var b = new object();
        try
        {
         **** Logic ****
        }
        catch (Exception ex)
        {
         **** Return Error ****
        }

        return b;
    }

API Config

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute(
            origins: "*",
            headers: "*",
            methods: "*");

        // Web API configuration and services
        config.EnableCors(cors);

        var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
        var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];

        config.MessageHandlers.Add(new JsonWebTokenValidationHandler()
        {
            Audience = clientID,  // client id
            SymmetricKey = clientSecret   // client secret
        });

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }





}

The Angular Request

  function postLogin() {
            var loginPackage = [];
            if (token === null) token = store.get('token');
            if (store.get('profile') != null) {
                loginPackage = store.get('profile');
            }

            return $q(function(resolve, reject) {
                $http({
                        method: 'Post',
                        url: BASE + 'profile',
                        data: loginPackage,
                        crossDomain: true,
                        xhrFields: {
                            withCredentials: true
                        },
                        contentType: 'application/json'
                    })
                    .success(function(data, status) {
                        *** Logic ***
                        resolve(function() {
                            resolve(true);
                        });
                    })
                    .error(function(data, status) {
                            reject(function() {

                            });
                    });
            });

        }

I think I may have been looking at this for too long and have overlooked something fairly simple.

////**** Update ****////

Response:

HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:17:26 GMT
Content-Length: 709

//* UPDATE *///

With a clean browser cache REQUEST (Fails)

POST /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 2372
Accept: application/json, text/plain, */*
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Authorization: Bearer null
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

I thought this may be the pre-flight but it is my understanding that would be with the OPTIONS verb not the POST verb.

The authorisation is not correctly set by the looks of it.

Authorization: Bearer null

The Response:

HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:31:49 GMT
Content-Length: 709

A second Post is sent immediately after and is successful. It is actually the pre-flight.

The Request:

OPTIONS /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Access-Control-Request-Headers: authorization, content-type
Accept: */*
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

And the Response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/10.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: authorization,content-type
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcaWFteWFcRGVza3RvcFxOZXcgZm9sZGVyICgzKVx3ZWJhcGlcQXBpXHByb2ZpbGU=?=
X-Powered-By: ASP.NET
Date: Sun, 08 Jan 2017 00:34:43 GMT
Content-Length: 0

Because of this I can not get beyond the login view. The loading screen sits on error. If I refresh and login again there is no error.

The Request:

POST /profile HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 2367
Accept: application/json, text/plain, */*
Origin: http://localhost:62379
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ltdC5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8MTAxNTM4MjIxOTc4MTIyNTEiLCJhdWQiOiJWWDhHMFMyUWM5cUFjYnRrM09pMVZMa2NkWGxnWlBtZSIsImV4cCI6MTQ4Mzg3MTMyNywiaWF0IjoxNDgzODM1MzI3fQ.HBQcGC6aad2pLaq3nPuhojrFT2b6Usv64p97b-DCRCU
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:62379/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6

The Authorization field now has the token instead of the null value:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3ltdC5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8MTAxNTM4MjIxOTc4MTIyNTEiLCJhdWQiOiJWWDhHMFMyUWM5cUFjYnRrM09pMVZMa2NkWGxnWlBtZSIsImV4cCI6MTQ4Mzg3MTMyNywiaWF0IjoxNDgzODM1MzI3fQ.HBQcGC6aad2pLaq3nPuhojrFT2b6Usv64p97b-DCRCU

The response is success and login proceeds.

The token seems to be injected only after a refresh.

My AUTH0 Config is:

 authProvider.init({
        domain: A0_DOMAIN,
        clientID: A0_CLIENT,
        callbackUrl: location.href,
        loginState: 'out.login',
        options:options
    });



    var refreshingToken = null;
    jwtInterceptorProvider.tokenGetter = function(store, jwtHelper) {
        var token = store.get('token');
        var refreshToken = store.get('refreshToken');
        if (token) {
            if (!jwtHelper.isTokenExpired(token)) {
                return store.get('token');
            } else {
                if (refreshingToken === null) {
                    refreshingToken = auth.refreshIdToken(refreshToken)
                        .then(function(idToken) {
                            store.set('token', idToken);
                            return idToken;
                        })
                        .finally(function() {
                            refreshingToken = null;
                        });
                }
            }
        }

    };

    jwtOptionsProvider.config({
        whiteListedDomains: ['localhost','https://www.ymtechno.com','https://www.ymtechno.com/_api','https://ymtechno.com/_api']
    });

    $httpProvider.interceptors.push('jwtInterceptor');

})
.run(function($rootScope, auth, store, jwtHelper, $location) {
    var refreshingToken = null;
    $rootScope.$on('$locationChangeStart',
        function() {
            var token = store.get('token');
            var refreshToken = store.get('refreshToken');
            if (token) {
                if (!jwtHelper.isTokenExpired(token)) {
                    auth.authenticate(store.get('profile'), token);
                } else {
                    if (refreshingToken === null) {
                        refreshingToken = auth.refreshIdToken(refreshToken)
                            .then(function(idToken) {
                                store.set('token', idToken);
                                return idToken;
                            })
                            .finally(function() {
                                refreshingToken = null;
                            });
                        return refreshingToken;
                    } else {
                        $location.path('login');
                    }
                }
            }

        });

    auth.hookEvents();
  • I don't program `.net` but what stood out to me was that you have `[AcceptVerbs("OPTIONS")]` but your `EnableCors` says to allow `*` methods. It seems that your web framework is overriding the headers you are trying to add manually. You should let your framework define these headers. Check your annotations. – Rafael Jan 07 '17 at 06:04
  • I thought that was correct but after clearing my cache I get the same error again. Once I get the first error I can log in no problem. – Bob Robertson Jan 07 '17 at 06:10
  • remove this `[AcceptVerbs("OPTIONS")]` – Rafael Jan 07 '17 at 18:41
  • Please provide the raw http response – Rafael Jan 07 '17 at 18:46
  • Response is now included. – Bob Robertson Jan 08 '17 at 00:24
  • even I had this issue, the first request failed with 500 XMLHttpRequest cross-origin error, and then the second request worked, it turned out my code had really a mistake and was throwing an exception, it was in fact reporting as cross-origin error, but actually it was another exception, it would be best to debug and check yourself. – Vignesh.N Jan 10 '17 at 12:40
  • The reason it is a CORS error is because the token is null and that is what is expected for Cross Origin. The injector seems to be firing before but not after auth. When the browser refreshes the token is available and injected because it is still in the browser cache. I am finally getting a chance to look at the code today. I will post any updates / solutions. I think I need to fire a function post login to update the token in the store and then fire a call to my API. Currently I am using .then to wait until after auth to call the api but the interceptor starts with the application. – Bob Robertson Jan 16 '17 at 07:45

1 Answers1

1

After investigating I found the interceptor was not putting the token into the auth header until the application was restarted. This was read as a CORS error because the request was not meeting the criteria for accessing the API. The token value was undefined.

A more in depth thread about injectors and headers can be found here:

Set HTTP header for one request

in the event that you come across the same issue it is a useful reference.

Community
  • 1
  • 1