Issue
I am facing the OAuth issue, details are below: I am having two microservices: registration-service(https://github.com/choudharylakshyaveer/registration-service) student-service(href="https://github.com/choudharylakshyaveer/student-service" rel="nofollow noreferrer">https://github.com/choudharylakshyaveer/student-service)
For these two I have added : cloud-config-server(https://github.com/choudharylakshyaveer/cloud-config-server) naminig-server(https://github.com/choudharylakshyaveer/naming-server) gateway(https://github.com/choudharylakshyaveer/api-gateway)
FrontEnd: is at react js: https://github.com/choudharylakshyaveer/chargie
For first time use, a new user need to be register that can be done from curl:
curl --location --request GET 'http://localhost:8765/user/save' \
--header 'Content-Type: application/json' \
--data-raw '{
"username": "[email protected]",
"password": "chaudhary22",
"enabled": true,
"roles": [
"ROLE_ADMIN",
"ROLE_USER"
]
}'
To login using the above registered user, below can be run from cUrl:
curl --location --request POST 'http://localhost:8765/login' \
--header 'Content-Type: application/json' \
--data-raw '{
"username": "[email protected]",
"password": "chaudhary22"
}'
Once I log In and get the Bearer token, after that I am facing cors issue from the reactJs FE, bu same request is working fine from the Postman, below is request from postman:
curl --location --request GET 'http://localhost:8765/REGISTRATION-SERVICE/test' \
--header 'Access-Control-Allow-Credentials: true' \
--header 'Access-Control-Allow-Headers: content-type' \
--header 'Access-Control-Allow-Methods: PUT, POST, GET, DELETE, PATCH, OPTIONS' \
--header 'Access-Control-Allow-Origin: *' \
--header 'Access-Control-Max-Age: 1800' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJyb2xlIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwic3ViIjoibHZzIiwiaWF0IjoxNjU4OTM0NzIxLCJleHAiOjE2NTg5NjM1MjF9.MN6lCrwLB2bBDBLp-HG4nlSRlyhoR2cQDSRGvJCD2WwDMojhei0wW7xVuDwVCtRUANK02aQMhqagafB2csDWWg'
Below is the code used to hit request from ReactJs FE:
var config = {
method: 'get',
url: 'http://localhost:8765/REGISTRATION-SERVICE/test',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Max-Age': '1800',
'Access-Control-Allow-Headers': 'content-type',
'Access-Control-Allow-Methods': 'PUT, POST, GET, DELETE, PATCH, OPTIONS'
},
Authorization: `Bearer ${token}`
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
And this request gives me CORS issue:
Snippet of the ServerSecurityContextRepository's overridden method used in SecurityContextRepository class of api-gateway:
@Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
ServerHttpRequest request = swe.getRequest();
HttpHeaders headers = request.getHeaders();
String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring(7);
Authentication auth = new UsernamePasswordAuthenticationToken(authToken, authToken);
return this.authenticationManager.authenticate(auth).map((authentication) -> {
return new SecurityContextImpl(authentication);
});
} else {
return Mono.empty();
}
}
Here when the request is coming from the Postman then below is receievd in the headers
variable:
[access-control-allow-credentials:"true", access-control-allow-headers:"content-type", access-control-allow-methods:"PUT, POST, GET, DELETE, PATCH, OPTIONS", access-control-allow-origin:"*", access-control-max-age:"1800", authorization:"Bearer eyJhbGciOiJIUzUxMiJ9.eyJyb2xlIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwic3ViIjoibHZzIiwiaWF0IjoxNjU4OTM0NzIxLCJleHAiOjE2NTg5NjM1MjF9.MN6lCrwLB2bBDBLp-HG4nlSRlyhoR2cQDSRGvJCD2WwDMojhei0wW7xVuDwVCtRUANK02aQMhqagafB2csDWWg", user-agent:"PostmanRuntime/7.29.0", accept:"*/*", postman-token:"6c0d7a9a-dcde-45d7-8422-1476682db9f4", host:"localhost:8765", accept-encoding:"gzip, deflate, br", connection:"keep-alive"]
But when same request comes from Front end then below is receievd in the headers
variable and it seems to be malformed:
[host:"localhost:8765", connection:"keep-alive", pragma:"no-cache", cache-control:"no-cache", accept:"*/*", access-control-request-method:"GET", access-control-request-headers:"access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,access-control-allow-origin,access-control-max-age,authorization", origin:"http://localhost:3000", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36", sec-fetch-mode:"cors", sec-fetch-site:"same-site", sec-fetch-dest:"empty", referer:"http://localhost:3000/", accept-encoding:"gzip, deflate, br", accept-language:"en-US,en;q=0.9"]
So, Here I am not receiving proper Authorization header on backend's headers variable so that I can take Bearer token to validate it.
Solution
Working after adding cors, complete code below for SecurityWebFilterChain's method :
http
.exceptionHandling()
.authenticationEntryPoint((swe, e) -> {
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
});
}).accessDeniedHandler((swe, e) -> {
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
});
}).and()
.cors().configurationSource(request -> {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Arrays.asList("GET","POST","PUT","PATCH", "DELETE","OPTIONS"));
config.setAllowedHeaders(Collections.singletonList("*"));
return config;
})
.and()
.csrf().disable()
.and()
.formLogin().disable()
.httpBasic().disable()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers("/login").permitAll()
.pathMatchers("/user/save").permitAll() //line added
.anyExchange()
.authenticated()
.and().build();
Answered By - Lakshyaveer Chaudhary
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)