I have the following get request defined in my service:
createAuthorizationHeader(user, pass) {
let headers: HttpHeaders = new HttpHeaders;
headers = headers.append('Accept', 'application/json, text/plain, */*');
headers = headers.append('Authorization', 'Basic ' + btoa(user + ':' + pass));
headers = headers.append('Content-Type', 'application/json; charset=utf-8');
console.log(headers);
return this.http.get(this._loginUrl, {
headers: headers
});
}
The result is:
OPTIONS https://localhost:8443/delivery/all 401 ()
Failed to load https://localhost:8443/delivery/all: Response for preflight does not have HTTP ok status.
HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: null, ok: false, …}
I also have made the same post request with Postman, but everything works, so the local server works.
I can't figure out what am I doing wrong with my request.
The CORS contract requires that authentication not be required on the pre-flight OPTIONS request. It looks like your back-end is requiring authentication on the OPTIONS request and the GET.
When you access your back-end with Postman, you are only sending a GET.
The browser will send an OPTIONS request first (without your authentication header), and look for the response to have an "Access-Control-Allow-Origin" header that matches the origin of the page making the request.
If the response to the OPTIONS response is not a 2xx, or the header is not present, or the header does value does not match the requesting page's origin, you will get the error that you are experiencing, and the GET request will not be made.
TLDR; change your back-end to not require authentication for the OPTIONS method when handling the login url.
By default, browsers won't allow users to perform Cross-origin request.
From Angular to avoid this error, we can use the proxy configuration.
Suppose if angular ui is working on localhost:4200 and it wants to call the rest end point url, e.g: https://localhost:8443/delivery/all
The below steps will address this issue.
Create a proxy.config.json file in your angular application root folder. (Where package.json file exist)
Proxy does is to simply take the browser request at the same domain+port where you frontend application runs and then forwards that request to your backend API server. CORS is a browser security issue and does not apply when doing “backend to backend” communication as is the case with a proxy in between.
The content should look as follows.
Sample:
{
"/delivery/all/*": {
"target": "https://localhost:8443",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
All requests made to /delivery/all/... from within our application will be forwarded to https://localhost:8443/delivery/all/
Note: the changeOrigin property. You will definitely have to set this to true when you’re using some virtual proxies (such as configured with Apache2) on your backend
Add proxy configuration while running application. Angular supports "--proxy-config" where you can supply the proxy configuration file.
If you are using the "npm start" option for testing, you have to add "--proxy-config" option as given below. It has to be added in package.json file.
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.config.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
If you are running directly using "ng serve" then it has be modified as given below.
"ng serve --proxy-config proxy.config.json"
The HTTP call inside our Angular application can be changed to this. Server will automatically forward the request to "https://localhost:8443/delivery/all".
this.http.get('https://localhost:8443/delivery/all')
.map(res => res.json());
to
this.http.get('/delivery/all')
.map(res => res.json());
here is link for more information: https://sudhasoftjava.wordpress.com/2018/10/05/proxy-configuration-in-angular/
@Daryl
What we've done is add a custom configuration for Cors. And then enable it through the security configuration in the java server. This Server was only enabled for direct REST calls as explained in the answer.
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
}
And this goes into the web security configuration:
@Override
protected void configure(final HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/**")
.authorizeRequests().and()
.httpBasic()
.and()
.authorizeRequests().anyRequest().authenticated().and().cors();
}