Axios 401 with GET, OPTIONS method - java

I'm going through an issue with Axios and a Java API.
I'm using this in my
Application.java:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
};
}
It worked great until today because I needed to use a Basic Auth in the provided api my get request like this (it works great in both PostMan and Chrome) :
axios({
method: 'get',
url: 'http://localhost:8180/unv-api/api/rubriques/1527/appli',
withCredentials: true,
headers:{ Authorization:'Basic '+btoa('admin' + ':' + 'password')}
})
with axios, an ACTION method is performed and returns a 401 error + a CORS error.
Any idea? Thanks.

Related

Ionic calls to backend not working on smartphone

Calls from my ionic app to my backend don't work on the smartphone. They work in the browser and in the emulator, but when I install the apk on the smartphone, it doesn't work.
My frontend is in ionic with capacitor.
My backend is java with Springboot.
This is my backend call:
url = `${SERVER_URL}/recipe`;
constructor(private httpClient: HttpClient, private alertController: AlertController) { }
findByIngredients(urlIds): Observable<Recipe[]> {
return this.httpClient.get<Recipe[]>(this.url + urlIds)
.pipe(
retry(2),
catchError(this.handleError))
}
findLastTen(): Observable<Recipe[]> {
return this.httpClient.get<Recipe[]>(`${this.url}/lastTen`)
.pipe(
retry(2),
catchError(this.handleError))
}
This is my backend cors configuration:
#Configuration
public class CorsConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "TRACE");
}
}
This is one of my endpoints:
#RestController
#RequestMapping("/recipe")
public class RecipeController {
#Autowired
private RecipeFacade facade;
#GetMapping(value = "/lastTen")
public ResponseEntity<List<GetAllRecipesDTO>> getLastTenRecipes() {
List<GetAllRecipesDTO> dto = facade.getLastTenRecipes();
return new ResponseEntity<>(dto, HttpStatus.OK);
}
Error message that is returned:
http failure response for http://...:9000/recipe/lastTen: 0 Unknown Error

Angular sends null Authorization Header

I am trying to send a request with an authorization header with Angular to a Spring backend.
export class TokenInterceptor implements HttpInterceptor{
constructor(public sharedService : SharedService){}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const jwtToken = this.sharedService.getJwtToken();
if(jwtToken){
req = this.addToken(req, jwtToken)
}
return next.handle(req)
}
addToken(req: HttpRequest<any>, jwtToken: any){
return req.clone({
headers: req.headers.append('Authorization', 'Bearer ' + jwtToken)
});
}
}
This is what my interceptor looks like. If I try to console.log() the authorization header before returning the next().handle , I can see the correct token inside the request. The problem is that the backend instead recieves a null Authorization header.
Inside by backend I have a doFilterInternal() method that filters any request and gets the Authentication header.
I don't think the problem is inside this filter because the request sent with Postman are handled correctly.
I have already enabled CORS on my backend
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("Authorization")
.allowCredentials(true)
.maxAge(3600L);
}
I believe token is not set, because headers property is read-only.
Try to use setHeaders property of clone method argument:
addToken(req: HttpRequest<any>, jwtToken: any){
return req.clone({
setHeaders: { Authorization: 'Bearer ' + jwtToken }
});
}
After banging my head against the wall for several hours I found the solution.
When creating a class and implementing the WebMvcConfigurer (to enable CORS) this is right and it SHOULD work.
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry corsRegistry){
corsRegistry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("Authorization")
.allowCredentials(true)
.maxAge(3600L);
}
}
BUT this isn't enough, since I had to enable CORS also into the security config chain
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http.cors().and().csrf().disable();
return http.build();
}
by tiping http.cors()

Spring Security+ReactJS - Preflight Request

I am working on a project with FE as react and BE as Springboot. I am trying to add FE to the application. After registration, I have tried to login to the application. After successful login, we get JWT Token. For that we need to send username, password and grant type in body and Basic authentication details in header. The is
var postData = {
username: a,
password: b,
grant_type:'c'
};
let axiosConfig = {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Origin": "*",
"Accept": "application/json" ,
"Authorization":"Basic" + " " +base64.encode("U" + ":" + "p")
}
};
axios.post('http://localhost:9003/login/token', postData,axiosConfig)
.then((res) => {
console.log("RESPONSE RECEIVED: ", res);
})
.catch((err) => {
console.log("AXIOS ERROR: ", err);
})
When I run this program, I got the error,
Access to XMLHttpRequest at 'http://localhost:9003/login/token' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And My Spring boot Code is
#Override
#CrossOrigin(origins = "*", allowedHeaders = "*") public void
configure(HttpSecurity http) throws Exception {
http.cors().and().exceptionHandling() .authenticationEntryPoint( (request,
response, authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and().authorizeRequests().antMatchers("/*").authenticated().and().httpBasic();
http.exceptionHandling().authenticationEntryPoint(new
CustomAuthenticationEntryPoint());
}
#Override
#CrossOrigin(origins = "*",allowedHeaders="*")
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.pathMapping("/oauth/token", "/login/token").tokenStore(tokenStore())
.tokenEnhancer(jwtAccessTokenConverter()).authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
Anybody know how to solve this?
As per MDN docs, the pre-flight response headers for a credentialed request should include a specific set of Access-Control-Allow-Origin and not a wild-card * .The cors config for the service can be setup by extending the WebSecurityConfigurerAdapter.
We faced a similar challenge with our spring-boot project and the following configuration helped overcome the cors failure
#EnableWebSecurity
public class DefaultAuthConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors(cors -> {
CorsConfigurationSource cs = resources -> {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000","http://localhost:3001"));
corsConfiguration.setAllowedMethods(List.of("POST", "GET", "PUT", "DELETE", "OPTIONS"));
corsConfiguration.setAllowedHeaders(List.of("Authorization",
"Content-Type",
"X-Requested-With",
"Accept",
"X-XSRF-TOKEN"));
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
};
cors.configurationSource(cs);
});
}
}
This class below to config CORS policy it worked for me.And i think your poblem is #CrossOrigin should be located in controller class.
#Configuration
public class AppConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
If you want more config follow this link https://spring.io/guides/gs/rest-service-cors/

Despite have a function for CORS, Spring application is responding with 406

Assume that Project is our POJO class. Following function provides to delete a row from database. It is successfully working with POSTMAN requests.
#RestController
#RequestMapping(value = "/project")
#CrossOrigin
public class ProjectController {
private final ProjectServiceImpl projectServiceImpl;
------------
#DeleteMapping
#RequestMapping("/delete/{id}")
public ResponseEntity<Boolean> deleteProject(#PathVariable Long id) {
boolean result = projectServiceImpl.delete(id);
return ResponseEntity.ok(result);
}
------------
}
But requests from Angular project are rejecting with 403 message. And following message is appearing in console screen.
After some searches. I learned, the application have to answer pre-flight requests with 200. To provide this, following function was added to controller.
#GetMapping
#RequestMapping("/delete/{id:[0-9]+}")
public ResponseEntity.BodyBuilder retreive(#PathVariable Long id) {
return ResponseEntity.ok();
}
I used regex for request mapping because without it Spring Framework throws /project/delete/{id} already mapped with another function. Angular get its 200OK for pre-flight request with this way. But the application response is 406 for delete operation. Angular is sending http://localhost:8080/project/delete/2 url to the application. If I send same link without have a function for CORS. Row has id with 2 will delete successfully. Am I missing something?
Sources:
Why Angular sending OPTIONS message before DELETE
How to add CORS support to Spring Boot application
To implement server side proxy: proxy.conf.json
{
"/project/**": {
"target": "http://localhost:8080",
"secure": false
}
}
modified section in angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "issue-management:build",
"proxyConfig": "proxy.conf.json"
},
and Angular project started with ng serve --proxy-config proxy.conf.json but result didn't change. Plus, suggestions in this article applied, again result didn't change.
Your applications are running on two different ports, that causing the CORS issue.
Add the proxy(file proxy.conf.json) in your Angular application.
{
"/project/**": {
"target": "http://localhost:8080",
"secure": false
}
}
and run this ng serve --proxy-config proxy.conf.json
Refference Angular doc
Update:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("*")
.allowedOrigins("http://localhost:4200");
}
};
}
worked, For some reason Angular proxy is not working
If you are using spring security use the following:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors(withDefaults())
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
See spring documentation: https://docs.spring.io/spring-security/site/docs/current/reference/html5/#cors
Global configuration:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Value("${cors.origins.urls}")
public String allowedOrigins;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedOrigins(allowedOrigins.split(","));
}
}

Spring boot & security - cors

According to the spring boot documentation I added bean
#Bean
WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
};
}
to enable global access from localhost:3000 , which is my frontend app.
I also use spring security, so if user enter localhost:8080/something he is redirected to login page ( if not logged ) . The problem is that this global cors configuration doesn't work.
I have simple controller which returns
List<String>
On the other hand I have angular service, which is responsible for making a get request to the server. It looks like this :
this.http.get("http://localhost:8080/words", {
headers: new Headers({
'Authorization': 'Basic ' + btoa('login:password')
})
}).map((res:Response) => res.json())
.subscribe(
data => { this.words = data},
err => console.error('Error : ' + err),
() => console.log('done')
);
and as a result I can see in google chrome console :
XMLHttpRequest cannot load http://localhost:8080/words. Response for preflight is invalid (redirect)
How can I fix this ?
This is because your front end application makes an OPTIONS HTTP before actual data transfer happens. Try adding this configuration to your spring project:
#Configuration
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
#Value("${angular}")
private String angularOrigin;
#Bean
public WebMvcConfigurer corsConfigurer(){
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins(angularOrigin)
.allowedHeaders("Authorization", "Cache-Control", "Content-Type", "Accept", "X-Requested-With", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Origin")
.exposedHeaders("Access-Control-Expose-Headers", "Authorization", "Cache-Control", "Content-Type", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Origin")
.allowedMethods("PUT","GET","POST","DELETE","OPTIONS");
}
};
}
}

Categories

Resources