10

Im' newbie using Angular HttpClient (and writting english too)

I have a problem, I'm trying sending HTTP request with POST method in order to negociate OAuth token obtenction but angular sends OPTIONS request:

Service:

login(username: string, password: string) {
const body = `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&grant_type=password`;

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + btoa(TOKEN_AUTH_USERNAME + ':' + TOKEN_AUTH_PASSWORD)
  })
};  


return this.http.post<string>(AuthenticationService.AUTH_TOKEN, body, httpOptions);

Result:

enter image description here

For my backend, I'm using Spring Security and i added a filter to allow CORS:

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
}
3
  • 2
    it seems that your auth serveur is not on the same domain as your front end application and you are facing CORS(Cross-origin resource sharing) problem.
    – JEY
    Commented Feb 27, 2018 at 14:44
  • 1
    You cannot call the /token endpoint using XHR. It's supposed to be accessed from backend or a native application. Commented Feb 27, 2018 at 14:45
  • Will you serve your angular application from spring too, or will users download scripts from some other domain? Commented Feb 27, 2018 at 17:42

6 Answers 6

14

It is not angular related, it is your browser doing.

Check this issue.

I assume your server runs at localhost:8080, and your angular application at localhost:4200. Since, your request is a cross origin request, browser first sends an OPTIONS request to see if it is safe. At this point, your server returns a response with http code 401 which prevents the post request from being made. Either you have to do some config in your server or you can use webpack proxy. This is just for your local machine. If you serve your bundled angular application from your server, then you won’t have to do anything for production. I’ve been using this technique for quite some time, and it works just fine.

Example,

Users access my angular application from mydomain.com/ng-app I also serve my rest api from same domain, mydomain.com/api

So my application always make the request to the server it’s being served from which causes no problem in production.

For latter, you can do following

Create a proxy.conf.json at the root of your project (next to package.json) And put following inside

{
    "/api/": {
        "target": "http://localhost:8080",
        "secure": false,
        "changeOrigin": true
    }
}

In package.json, edit your start script and make it ng serve --proxy-config proxy.conf.json

Also, from your frontend, do not send the requests to localhost:8080 directly, instead just write something like http.post('/api/getSomeData') which will make the request to localhost:4200 which will redirect it to localhost:8080. This way, you won't have to deal with CORS.

8
  • that won't work if he is deploying this in production or on a server like apache or nginx
    – Mike Tung
    Commented Feb 27, 2018 at 15:03
  • If he is serving angular application from the same domain, it’ll work just fine. Commented Feb 27, 2018 at 15:05
  • assuming he uses webpack, it would work but if he was deploying this with some other than webpack then issue comes
    – Mike Tung
    Commented Feb 27, 2018 at 15:06
  • It is not about webpack. When you make request without mentioning the domain, it’ll make the request to the domain which serves the front end application. I’ve been doing the same thing with my project, and it works just fine Commented Feb 27, 2018 at 15:07
  • please see link because you run ng serve <blah> it uses webpack to run a development server to serve your angular application. Again if OP uses apache/nginx in a production setting this won't do.
    – Mike Tung
    Commented Feb 27, 2018 at 17:36
2

The OPTIONS request is sent first because of CORS, Angular needs permission from your backend in order to know if it can POST. So on your backend you need to enable CORS in order for the http request to go.

0

For spring boot application, to enable cors request, use @CrossOrigin(origins = "*", maxAge = 3600) on your respective controller.

Refer this

0

use angular cli configuration https://angular.io/guide/build#proxying-to-a-backend-server

0

With a NestJS/Express backend, I fixed this by enabling CORS: https://docs.nestjs.com/techniques/security#cors

-1

Finally I found the mistake. The order of the Filter there weren't correct. I adjusted it to Ordered.HIGHEST_PRECEDENCE this way it override Spring filter.

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}
4
  • Be careful though, you are allowing CORS which may result in security flaws. Commented Feb 28, 2018 at 6:48
  • Of course, this bean only apply in Development Enviroment Commented Feb 28, 2018 at 7:23
  • Check my answer, you would not need this bean even in development environment. Commented Feb 28, 2018 at 7:24
  • Using your proxy, Angular made a prefligth request and my backend block it. It answer don't work for me. Commented Feb 28, 2018 at 7:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.