(NodeJS / AngularJS) POST request with 'x-auth' token to server, but token seems to get lost in preflight (no error though) - angularjs

Background
I have a simple NodeJS server hosted on localhost/Heroku which handles JWT authentication for adding data to the registered user amongst other (unrelated) things.
Here's the GitHub: https://github.com/mlee93dev/pw-keychain-server
I also have a simple Angular2 client on localhost/Heroku for this server:
https://github.com/mlee93dev/pw-keychain-app
Currently, I have my JWT access tokens configured to last only 5 seconds in my server for development purposes.
I have my CORS stuff configured to the best of my knowledge as shown below in server.js:
CORS configuration pic
The Problem
On Postman I test the POST request and I get the expected response - a JWT expiration error:
Postman POST pic
However I don't get the same response on my client - rather, I get a 'JWT must be provided' error:
Client POST pic
As you can see in the pic above, I know I'm actually attaching a token as I console.log it. Here's a pic of the code:
Client POST code pic
So what's confusing me more is that my DELETE request (for logging out) also implements the same x-auth token to request code, and it works in both Postman + client, as seen here:
DELETE error response
DELETE code
So yeah, I'm pretty confused. My guess is I have to configure my CORS some more to allow x-auth header on POST requests specifically somehow? Even though I think it should do that already with my current configuration.

You are providing the body in post request instead of headers.
Angular POST request
So in your post request just do the following
this.http.post(yoururl, {},{headers:new Headers({'x-auth':token})})...
And it should work.

Related

IdentityServer API unauthorized if hosted in IIS

I added additional API to the Duende IdentityServer 6.2 as described here. Then I tried to access it from a sample App, using typed httpClient using their own library called AccessTokenManagement (aka Identity.Model) pretty much following their simple example. I use Authorization Code flow, everything pretty much simple and default.
It works well until both server and client are on the same dev machine under localhost. As soon as I publish IdentityServer to IIS, the API stops to work, while the rest still works well (I can be authenticated, and I see in the Fiddler that token exchanges work normally).
The call to API consists from two calls:
Calling to /connect/token using refresh token. Server returns access token.
Calling my endpoint using this new access token.
The flow fails on the step 1. Call to /connect/token is already unauthorized and I can't understand why. The "good" and "bad" calls looks the same, I cannot see any differences. Previous call moment ago to /connect/userinfo consists of the same two steps and it works. Logs on both server and client give no clues.
No reverse proxies, just good plain simple URI. Automatic key management is enabled and the keys are in the SQL table, common for dev and published server. Asp.Net Core Data Protection is enabled and keys are also common.
Relevant parts of logs are below. I noticed that "No endpoint entry found for request path" is specific to IdentityServer and it doesn't actually mean that endpoint was not found. It was found but not processed. I also noticed reacher response headers from bad request and log entry about "Cookie signed-in" in good request but not sure what does it mean and whether it's relevant.
I'm running out of ideas.
Bad response from IIS while trying to get new Access Token:
Proper response while developing:
///////Relevant part of log for BAD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: cookie was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://auth.mysite.org/connect/token
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Error refreshing access token. Error = Unauthorized
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://auth.mysite.org/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 117.7278ms - 401
///////Same part of GOOD request
|Duende.AccessTokenManagement.OpenIdConnect.UserAccessAccessTokenManagementService|Token for user test#test.com needs refreshing.
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies was successfully authenticated.
|Duende.AccessTokenManagement.OpenIdConnect.UserTokenEndpointService|refresh token request to: https://localhost:5001/connect/token
|Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler|AuthenticationScheme: Cookies signed in.
|System.Net.Http.HttpClient.IdsService.ClientHandler|Sending HTTP request POST https://localhost:5001/mycontroller/myaction
|System.Net.Http.HttpClient.IdsService.ClientHandler|Received HTTP response headers after 1994.9611ms - 200
///////Server log during BAD request
Duende.IdentityServer.Hosting.EndpointRouter No endpoint entry found for request path: "/mycontroller/myaction"
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler HandleAuthenticateAsync called
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was not authenticated.
Duende.IdentityServer.Hosting.LocalApiAuthentication.LocalApiAuthenticationHandler AuthenticationScheme: "IdentityServerAccessToken" was challenged.
Okay, found it. Thankfully, looked at Fiddler's WebView and had seen familiar picture!
Then, found this topic. The solution was disabling Basic authentication in IIS settings. Access token request has basic authentication header and it seems like IIS intercepts it. Still a bit unclear why other parts of flow worked.

Re-Captcha Angular CORS Issue

I am using Angular 1.x to POST a verification request to Google's re-captcha as follows:
var post_data = { //prepare payload for request
'secret':'xxxxx',
'response':fields.myRecaptchaResponse
};
$http.post('https://www.google.com/recaptcha/api/siteverify', post_data)
In my console I can see the following error:
XMLHttpRequest cannot load https://www.google.com/recaptcha/api/siteverify. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://igs.dev' is therefore not allowed access. The response had HTTP status code 405.
I have read multiple answers on Stackoverflow, most seem to suggest adding a plugin to Chrome but that is not a solution for my users who will be using the re-captcha to validate a contact form.
Is this a misconfiguration of my server or is my Angular script missing something? I have already ensured that my domain is configured in my re-captcha account.
ReCaptcha is validated on the server-side, not the client side. The CORS error is due to the fact that the ReCaptcha API is not meant to be used by a browser.
You need to send your recaptcha data to your API/server which then verifies it is correct by sending a request to the ReCaptcha API. There are no CORS restrictions when servers make HTTP requests to each other.
See this Tuts tutorial on how the implementation and flow of data works
The end point https://www.google.com/recaptcha/api/siteverify is part of server side validation and not the client side. You should hit this endpoint from your server, not from your client (Angular 1.X).
So the flow may look like this:
At your client side (Angular 1.X) you will be loading the re-captcha widget in your html which will perform the validation and store a hash value in a hidden input field which will be sent to your server along with the other form details when user submits the form. Now at your server side you will hit that endpoint to verify if the validation was successful.
Also, in no case you should be storing your secret at the client side. It should always be maintained at your server side for server-to-server communication purposes.
Read the docs here.

OPTIONS Error using twitter API (400)

For my personal website, I'd like to create a page summarizing my social presence.
I used Postman to make sure all my queries are valid.
So I made simple call to get my last post on twitter.
Everything works find on Postman, so there isn't any Authorization issues.
But when it comes to implement it on my client (using AngularJs ), I'm getting this error:
OPTIONS https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=1106474965 400 ()
XMLHttpRequest cannot load https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=1106474965. Response for preflight has invalid HTTP status code 400
I know it may be related to How does Access-Control-Allow-Origin header work? but I can't configure the server as I subscribed a shared hosting
(One.com).
I tried to reset my $httpProvider default values in vein.
It seems Twitter API doesn't support CORS headers, and that's why your preflight tests are failing:
https://twittercommunity.com/t/will-twitter-api-support-cors-headers-soon/28276

Nginx Web browser CORS Issues

I'm working on an AngularJS Application which uses an external API and I got a weird issue (CORS). I made a lot of research that does not fix the issue.
When I hit my API the preflight request is good (status 204 No-Content),
but when the server responds with a another status code than 2xx (200, 204 etc...) I got the CORS issue.
If my server send back 2xx as status code is alright we have no CORS issue but if another status code is sent here is the problem.
API :
Sylex(PHP Framework) running under Nginx
Front application :
AngularJS - using webpack
XHR VIEW :
Console CORS Error :
After a day of search I figured out where the CORS was coming from.
The Nginx configuration was ok. It was the API.
During the preflight request (OPTIONS) the server let passed the request because NGINX allowed the origin and header (access-control-allow-origin, access-control-allow-headers),
but when the API sends back the response the headers were not set up.
I fixed it by adding the access-control-allow-origin and access-control-allow-headers to the response.
IMPORTANT: I figured out data weren't recoverable in the response with the 200 status code on the webbrowser. To fix it remove the headers added in the others responses (5xx, 4xx, etc..)
(I don't know if its just in my case)
I haven't developed the API that's why it takes me a day to figure it out. Hope I will help someone with this use case :)

Communication with an API

I have a Symfony2 API and an AngularJS app which consumes it.
I'm facing a problem when trying to connect a member. It should work like this :
The client sends a POST request to the API, on the route /api/public/users/connection. The content of the request is a JSON object like this : {"username":"qzdqzd","password":"qzdqzdc"}
The server verifies the request and send back either a 400 response, with a body containing the error message (such as "This username does not exist."), or a 200 response, with the API key in the content to be stored in a cookie.
I'm facing a very strange problem. I have two instances of the API : one in my computer, in local, and the other one on the web (http://api.galaxia-online.com). When my AngularJS code is configured to request the local API, it works as expected :
It's in french, but you can see in red the error message.
But when I change my AngularJS code to request the distant API, with the same request, I receive a 400 error code, but with no content in the response. Plus, Firefox tells me that I have a CORS problem.
I thought at first that I misconfigured CORS on the server, but! When I try to do the exact same request with a dedicated browser addon (RESTClient in my case), it works perfectly :
So I start to think that the problem could be caused by AngularJS. The request seems valid, and seems to work as it do in RESTClient, but AngularJS doesn't receive anything.
I'll be grateful if someone has a clue.

Resources