HTTP POST turns into OPTIONS AngularJS - angularjs

I'm trying to submit a login form to a rest Api, translating my Jquery/Javascript code into AngularJS. I try to use $http service for send the request, but when I submit the form, the POST request turns into OPTIONS and no request params are passed to. This is my code:
controller.formData = {
username : $scope.formData.username,
password : $scope.formData.password,
};
$http({
method : 'POST',
url : 'http://localhost:8080/multe-web/signin',
data : controller.formData,
headers : { 'Content-Type': 'application/json' }
})
.success(function(data) {
console.log(data);
});
This is a screenshoot of browser's console
Why no parameters are passed to the HTTP POST request?
Can someone help me?

If you are trying to do a Cross Origin Request, this could be a 'preflight request':
See this post: How to disable OPTIONS request?

This request is called "preflight request". This appends when you try to access a resource that is from another domain. For more information you can search for Cross-origin resource sharing (CORS). During the preflight request, you should see headers starting with Access-Control-Request-* These request headers are asking the server for permissions to make the actual request. Your preflight response needs to acknowledge these headers in order for the actual request to work.

The OPTIONS that you see is a pre-flighted request that is initiated by the browser. This happens due to CORS that stands for "CROSS ORIGIN RESOURCE SHARING`.
Pre-flighted requests
In your case, your backend server needs to acknowledge the OPTIONS request and send a 200 back. Only then the browser fires the real POST request
Here are some links to get you started
Same Origin policy
AngularJS and CORS
Similar question on SO

You must define a CORS filter on your backend.
I don't know which language you are using but an example in spring framework (java) would be the following.
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, cache-control, content-type, Origin, key");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
Basically you are stating that response.setHeader("Access-Control-Allow-Origin", "*"); can come from any domain. ( in a production environment you would limit this offcourse to your known domains ).
When implementing this filter your options request will pass through without problems.
The options call is something the browser does automatically and you really don't want to disable this as some other answers are suggesting.
Kind regards

Related

Authorization header not visible in react app though its marked allowed in exposed header in spring server

I am using spring-boot-starter-parent with version 2.3.4.RELEASE and spring-security.
I have defined cors configuration as below in my spring boot app. I am able to make calls to REST API from react app running on my local without cors issue.
As part of login am hitting /user API with user credentials. Server sends user details as response and I am generating JWT in a filter only for /user API and sending JWT in Authorization header.
I have tested with postman and curl I can see the Authorization header but my react app though it can authenticate it can't see or access Authorization header or the JWT in the response of /user API.
In cors configuration I have marked Authorization header as exposed config.setExposedHeaders(Arrays.asList("Authorization")); not sure why its not getting reflected.
complete code is as below.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowCredentials(true);
config.setAllowedHeaders(Collections.singletonList("*"));
config.setExposedHeaders(Arrays.asList("Authorization"));
config.setMaxAge(3600L);
return config;
}
}).and()
.csrf().disable()
.addFilterBefore(new JWTTokenValidatorFilter(), BasicAuthenticationFilter.class) //JWT validation before basic authentication
.addFilterAfter(new JWTTokenGeneratorFilter(), BasicAuthenticationFilter.class) //JWT validation after basic authentication
.authorizeRequests()
.anyRequest().authenticated()//authorize all requests
.and()
.httpBasic();
}
I tried explicitly defining a cors filter but that didnt work either
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, x-requested-with, x-auth-token");
response.addHeader("Access-Control-Expose-Headers","Authorization");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) {
try {
chain.doFilter(req, res);
} catch (Exception ex) {
ex.printStackTrace();
}
} else {
System.out.println("Pre-flight");
response.setHeader("Access-Control-Allowed-Methods", "POST, GET, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Authorization, content-type,x-auth-token, " +
"access-control-request-headers, access-control-request-method, accept, origin, authorization, x-requested-with");
response.addHeader("Access-Control-Expose-Headers","Authorization");
response.setStatus(HttpServletResponse.SC_OK);
}
}
}

Getting a CORS issue when posting data from frontend(React)

I'm posting data from react to spring boot backend using axios. Please refer the below react code.
const handleSubmit = (e) =>{
e.preventDefault()
alert( "Username "+ username + " Password "+password);
axios.post('http://localhost:8080/sign-up',{
username:username,
password:password})
};
Below is my spring code.
#PostMapping("/sign-up")
public String signUp(#RequestBody User user) {
if(userRepository.findByUsername(user.getUsername())==null) {
Set<Role> roles= new HashSet<>();
Role role= roleRepository.findByName("USER");
roles.add(role);
user.setRoles(roles);
user.setPassword(bcryptEncoder.encode(user.getPassword()));
userRepository.save(user);
return "Success";
}
else{
return "Username Already Exsist";
}
}
When I post data from front end i'm getting below response in the browser console.
Access to XMLHttpRequest at 'http://localhost:8080/sign-up' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
xhr.js:178 POST http://localhost:8080/sign-up net::ERR_FAILED
createError.js:16 Uncaught (in promise) Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
I've inserted following line in the controller of the spring boot.
#CrossOrigin(origins = "http://localhost:3000")
But the above solution didn't work. I suspect during the post call option call is happening to check the resource and in that case only this cors issue is occuring. Appreciate any input to this issue.
I had a similar issue recently.
I got a first step further by removing spring-boot-starter-security from my POM temporarily, because it was blocking the call giving unauthorized. So I figured out that that was my problem. I had to configure CORS for Spring security and then I got it to work. Apologies for the vague answer, but I hope it can help you look in another direction that could help you.
I have found the solution for the above problem. This cors issue is coming when there is a communication happening between different domains. So I have added below line in the configure() method of SecurityConfig class.
http.cors();
Then I have implemented the following CustomCorsFilter class.
#Component
public class CustomCorsFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Allow, authorization, content-type, xsrf-token");
httpServletResponse.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(httpServletRequest.getMethod())) {
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
}
Now there is no cors issue.

How to make POST request to external API using Angular2?

I'm trying to leverage CORS to make a post request. I came across several articles/answers related to CORS but somehow just couldn't get it working.
As I understand, the access-control-allow-origin: * is to be set on the server side to get this working but what I have here is a angular-cli project.
My project is purely Angular 2.1 based and no backend server is involved. Any suggestions as to how to set it up properly will be highly appreciated.
The exact error that I'm getting is this:
"NetworkError: 404 Not Found - https://flowxo.com/hooks/a/rbpja7r2/?usertype=User"
and this warning in console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the
remote resource at https://flowxo.com/hooks/a/rbpja7r2/?usertype=User.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).
Update:
Here's how I'm trying to make a POST request:
let headers = new Headers();
headers.append('Access-Control-Allow-Headers', 'Content-Type');
headers.append('Content-Type', 'application/json');
headers.append('Access-Control-Allow-Methods', 'POST, OPTIONS');
headers.append('Access-Control-Allow-Origin', '*');
return this.http.post(
this.flowxoUrl,
JSON.stringify(formData),
{headers: headers}
)
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error')); //...errors if any
This is server side issue, not Angular.
Your server should respond with Access-Control-Allow-Origin header.
Java (Spring) example:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "*"); //you can specify domains here * - is a wildcard, it will allow all origins to request
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type");
if("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
#Override
public void destroy() {}
}

Cross-Origin Request Blocked, angularjs rest call to jersey api

I'm completely stumped. I am very new to AngularJS and I am trying to make a rest call to my jersey server api but I am having no luck. It works using curl or Advanced Rest client (Chrome browser add-on). However I recevied the following when attempting to hit my rest using my angularjs app..
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/JerseyDemos/rest/employees. (Reason: CORS header 'Access-Control-Allow-Origin' missing)."
CLIENT: snippet of my angularjs code
$scope.login = function() {
This lets me connect to my server on a different domain
$http.defaults.headers.common['Authorization'] = 'Basic ' + Base64.encode('username' + ':' + 'password');
$http({method: 'GET', url: 'http://localhost:8080/JerseyDemos/rest/employees'}).
success(function(data) {
console.log(data)
}).
SERVER: I am using jersey framework
Heres my CORS Filter...
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
Application class to register my CORS Filter
import com.howtodoinjava.jersey.provider.CorsResponseFilter;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import com.howtodoinjava.jersey.provider.AuthenticationFilter;
import com.howtodoinjava.jersey.provider.GsonMessageBodyHandler;
public class CustomApplication extends ResourceConfig {
public CustomApplication()
{
packages("com.howtodoinjava.jersey");
register(CorsResponseFilter.class);
register(LoggingFilter.class);
register(GsonMessageBodyHandler.class);
register(AuthenticationFilter.class);
}
}
Web.xml
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.howtodoinjava.jersey.CustomApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Employee rest snippet
#Provider
#Path("/employees")
public class JerseyService {
#Path("/all")
#RolesAllowed("ADMIN")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getAllEmployees()
{
Employees list = new Employees();
list.setEmployeeList(new ArrayList<Employee>());
list.getEmployeeList().add(new Employee(1, "Lokesh Gupta"));
list.getEmployeeList().add(new Employee(2, "Alex Kolenchiskey"));
list.getEmployeeList().add(new Employee(3, "David Kameron"));
return Response.status(200).entity(list).header("Access-Control-Allow-Origin", "GET, POST, PUT, DELETE, OPTIONS, HEAD").build();
}
This is a very common error for people who are just getting started with Web Services, it’s really simple to solve but sometimes developers spend hours struggling to find a solution. It happens when you create a web service and tries to access it from a different application, it won’t work because you don’t have Cross-Origin Resource Sharing (CORS) enabled, which means an application loaded in one domain cannot interact with resources from a different domain. All you have to do is to enable CORS.
How you can active it will depending on your scenario, in this tutorial I’m going to show how to enable CORS for a Java EE application running on Glassfish, I’m assuming you have an EJB RESTful web service similar to this one, and when other applications tries to consume it you see the Cross-Origin Request Blocked error on your firebug console, in this case all you have to do is to create a filter in your application, just create a class exactly like this one on your project:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CORSFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, HEAD, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Origin, Accept, x-auth-token, "
+ "Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
Now you have to register the filter in your web.xml, copy the following code and replace “yourPackage” with your actual package name:
<filter>
<filter-name>cors</filter-name>
<filter-class>yourPackage.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
That’s it! Now your application will allow its resources to be shared with other domains.
Other Cross-Origin Request fix..

how to enable CORS with Vert.x 2.x

I am trying to make cross-domain requests with Angularjs 1.4.5.
But can't get success. I have configured $httpprovider
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common['Accept']= "application/json, text/plain, */*";
$httpProvider.defaults.headers.put["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=utf-8";
$httpProvider.interceptors.push('authenticationFailedInterceptor');
}])
But still con't get success. How to enable CORS support with Vert.x 2.x http server.
CORS is supported in Vert.x 3.x but Right now I can't upgrade Vert.x.
have you tried with something like this on your responses?
vertx.createHttpServer()
.requestHandler(function (req) {
req.response()
.putHeader("content-type", "text/plain")
.putHeader("Access-Control-Allow-Origin", "*")
.putHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
.putHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
.end("Hello from Vert.x!");
}).listen(8080);
for sure, you have to modify this to your needs... but the changes has to be done in the server and at least, you need these three headers.
Complete example to enable cors:
We need to create two route matcher.
One helps to enable cors and other handle the requests.
Below is to enable cors. It Accept all request and add all the required headers needs to enable cors. After that we need to hand over request to the actual route matcher to handle request. We have that by the name secureRoutes.
RouteMatcher routeMatcher = new RouteMatcher();
routeMatcher.options(".*",new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Access-Control-Allow-Origin", "*");
request.response().putHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
request.response().putHeader("Access-Control-Allow-Headers", "accept, authorization, content-type, email");
request.response().end();
}
})
.all(".*",new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Access-Control-Allow-Origin", "*");
secureRoutes.getRouteMatcher().handle(request);
}
});
Another route matcher:
public class SecureRoutes {
private static final RouteMatcher routeMatcher = new RouteMatcher();
#Inject
protected Container container;
#Inject
private SigninController signinController;
#Inject
private SignupController signupController;
#Inject
private OauthController oauthController;
#Inject
ClientNetworkSignalController clientNetworkSignalController;
public void initRoutes() {
// APP routes. they use User token for authentication
routeMatcher.get("/", new Handler<HttpServerRequest>() {
#Override
public void handle(final HttpServerRequest request) {
request.response().putHeader("Cache-Control",
"public, max-age=86400");
request.response().sendFile("web/public/index.html");
}
});
routeMatcher.post("/signin", signinController.signin());
routeMatcher.post("/signup", signupController.signup());
routeMatcher.post("/oauth2/token", oauthController.token());
routeMatcher.post("/oauth2/invalidate_token", oauthController.invalidateToken());
}
public RouteMatcher getRouteMatcher() {
return routeMatcher;
}
}
Now finally add requestHandler to server:
server.requestHandler(routeMatcher).listen(port,
host, new Handler<AsyncResult<HttpServer>>() {
public void handle(AsyncResult<HttpServer> asyncResult) {
if (asyncResult.succeeded()) {
logger.info(s + ": Started on " + host + ":"
+ port);
} else {
logger.info(s + ": Unable to start server.\n "
+ asyncResult.cause());
}
}
});
You may have a question What is the use of http options type request handler. The answer is for that is very interesting. Javascript is a secured language that do not allow Cross origin Http request. So, to allow cross origin request javascript send a options type request for each http request request and check weather CORS is supported or not. In such Javascript hits server two times one to check cors is supported or not and one to fatch data.

Resources