I'm trying to set up a login screen on my react app. This provides authorisation to my spring boot backend to provide the data I need displayed. However, I keep getting the following error message from Chrome:
Access to fetch at 'http://localhost:8102/users' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I've tried the following and they don't seem to work:
In my React app:
Login.js
...
login = () => {
const user = {username: this.state.username, password: this.state.password};
fetch(SERVER_URL + "/login", {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
method: 'POST',
body: JSON.stringify(user)
})
.then(response => {
const jwtToken = response.headers.get("Authorization");
if(jwtToken != null) {
sessionStorage.setItem("jwt", jwtToken);
sessionStorage.setItem("username", this.state.username);
this.setState({ isAuthenticated: true });
} else {
this.setState({ open: true });
}
})
.catch(err => console.error(err));
}
...
In my App.js:
class App extends Component {
constructor(props) {
super(props);
this.state = { user: "user" };
}
componentDidMount() {
fetch(USER_URL)
.then((response) => response.json())
.then((responseData) => { this.setState({ user: responseData._embedded.user }); })
.catch((err) => console.error("THIS IS A SERIOUS ERROR INDEED!" + err));
}
render() {
return(
<div className='App'>
<Login />
</div>
)
}
}
On my Spring Boot backend:
SecurityConfiguration.java
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated()
.and().addFilterBefore(new LoginFilter("/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
...
...
#Bean
protected CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowCredentials(true);
config.applyPermitDefaultValues();
source.registerCorsConfiguration("/**", config);
return source;
}
...
In my MainController.java1
#RestController
#CrossOrigin
public class MainController {
...
None of that seems to be properly working to get around this CORS issue.
My Server github repository is:
AssetRegister-Server
My Client github repository is: AssetRegister-Client
To make sure that spring security actually uses CORS, you have to actually enable it.
Its not enough to just register a configuration as a #Bean.
you enable CORS in you security config like this:
http.csrf().disable()
.cors()
.and()
.authorizeRequests()
Other things to point out in your code base:
#CrossOrigin can be removed since you are are defining CORS using spring security.
You have implemented a some sort of custom login solution when spring security already has something called formLogin all you need to do is enable formLogin and then send the data using javascript fetch as form data
fetch and form data and then you can remove your entire custom login. Writing custom login as you have done is bad practice, and if you would submit this code in production or to learn, you are learning very bad practices.
Spring security comes already with a JWT library built in called Nimbus, so there is no need to pull in a different one as you have done.
Using JWTs as sessions comes with security risks and there are several blogs talking about that you should not use them as sessions json-web-tokens-jwt-are-dangerous-for-user-sessions Why JWTs Suck as Session Tokens You should think about this before using JWTs as session tokens. The way they you have them implemented now you have no possibility of revoking tokens so if someone steals a token, then you cant stop them from using it maliciously until it times out.
Benefits by using formLogin is that you can use the authenticationSuccess handler to return a session/token
.formLogin(formLoginSpec -> formLoginSpec.loginPage("/login")
.authenticationFailureHandler(new AuthenticationFailureHandler())
.authenticationSuccessHandler(new AuthenticationSuccessHandler())
So what im trying to say is that if you are following a tutorial etc. Then it is very out of date, or it has no idea about what actually exists in spring security. And i recommend that you look into the official documentation. Its very good.
Try replacing #CrossOrigin with #CrossOrigin(origins = "*", allowedHeaders = "*") in MainController.java
Related
I have created a react app with a spring boot backend but I'm having trouble pulling the data through with axios.
I have checked numerous SO posts as well as documentation with spring to no avail. I was initially blocked by CORS but I was able to resolve that with Spring Security. However, spring security requires authentication, I've been using the default user "user" with the randomly generated password (since I can't get a newly defined user/password defined with AuthenticationManagerBuilder to work just with queries against the server directly in a browser but that's an issue for another day). Below is my configuration file for the server.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
http.cors().and();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
My server runs on localhost port 9898, the query I'm initially trying to pull data from on the front end is a get by id for contact info which goes against http://localhost:9898/api/Contact/1
when I successfully call the server from a browser directly the header details are as depicted:
call from browser to server general and response headers
call from browser to server request headers
notice that authorization header is actually there in the request.
For the RestController I've got cross origin set to the client running on port 3000. I do have a header being adding in the getContactMethod as suggested in a tutorial but I don't think this actually changed anything since I have this header being set in the configuration file anyway.
#CrossOrigin(origins = "http:localhost:3000")
#RestController
#RequestMapping("/api/Contact")
public class ContactController {
#Autowired
private ContactRepository ContactRepository;
#GetMapping("/")
public List<Contact> getContacts(){
return this.ContactRepository.findAll();
}
#GetMapping("/{id}")
public Contact GetContact(#PathVariable Long id, HttpServletResponse response){
response.setHeader("Access-Control-Allow-Origin", "**");
return ContactRepository.findById(id).orElse(null);
}
For the client I have a file creating an axios instance, I'm not sure if this part is right since I never reference the specific instance again but maybe axios can figure this out on it's own if there is only one instance.
import axios from "axios";
const api = axios.create({
baseURL: "http://localhost:9898",
});
// api.defaults.headers.common = {
// 'X-Requested-With': 'XMLHttpRequest'
// };
export default axios;
Now for the actual page on the front end I am attempted to load the requested data into the state variable from the useEffects event, which will need to be modified a little bit further but I can't go forward with that until the request works.
I've got numerous headers loaded in based on a combination of what I've come across online but the one I want to focus on is the authentication since that won't actually show up in the request when I look with dev tools on the network. I've got the password which is randomly set by spring security each time the back end is run hard coded and then this hard coded user:password value is encoded and added to the headers. Below is the relevant code:
const tok = 'user:9de3a921-a4af-4d51-b8d7-cf37b208916e';
const hash = btoa(tok);
const Basic = 'Basic ' + hash;
const headers = {
"Cache-Control": "no-cache",
"Accept-Language": "en",
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "http://localhost:3000",
"Access-Control-Allow-Methods": "DELETE, POST, GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
//"Authorization": "Basic dXNlcjowM2VhN2JhYS1mMTQ0LTQ5YWMtOGFhMy02NDE4YWJiNzdhMTk=",
'Authorization': `Basic ${hash}`,
};
useEffect(() =>{
console.log(Basic);
axios.get("http://localhost:9898/api/Contact/1", headers)
.then((res) => {
console.log("data " + res.data);
console.log("response header " + res.headers['Authorization']);
setInfo(res.data);
}).catch(err => console.log("error found " + err));
console.log(info);
}, []||[]);
When this is run I get a 401 unauthorized but for some reason the authorization header doesn't show up in the request headers.
General and response headers for request from client to server
Request headers for request from client to server
I feel like I'm fairly close with this but most of the tutorials on the spring site are simpler and the best practices for spring security have changed over the years so there is a lot of conflicting information and incomplete examples on the web. I figure I either have an issue in the security configuration or I guess I've set the headers up incorrectly but I don't have enough experience with spring and react I've just been troubleshooting in circles for a couple days.
Sources tried already (had to put some spaces in the links since I just made this account to post a question):
https://stackoverflow com/questions/36968963/how-to-configure-cors-in-a-spring-boot-spring-security-application/37610988#37610988
I should mention with this one below I added in .antMatchers(HttpMethod.Options, "/**").permitAll() and the headers were different but the request still didn't work and eventually the server would just crash shortly after starting with it
https://stackoverflow com/questions/41075850/how-to-configure-cors-and-basic-authorization-in-spring-boot/60933851#60933851
https://stackoverflow com/questions/58901586/how-to-fix-spring-security-authorization-header-not-being-passed
https://spring io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
https://spring io/guides/gs/rest-service-cors/
https://spring io/guides/gs/rest-service/
https://docs.spring io/spring-security/reference/reactive/integrations/cors.html
https://www.baeldung com/spring-security-cors-preflight
There is an issue with how the headers are are being passed to axios. The axios documentation defines axios.get like this axios.get(url[, config])
There are two parameters here. The first is the url, and it is required. The second is an optional config object.
The config object has a headers field.
You should pass in the headers like this:
const headers = {
'Cache-Control': 'no-cache',
'Accept-Language': 'en',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'http://localhost:3000',
'Access-Control-Allow-Methods': 'DELETE, POST, GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With',
//"Authorization": "Basic dXNlcjowM2VhN2JhYS1mMTQ0LTQ5YWMtOGFhMy02NDE4YWJiNzdhMTk=",
Authorization: `Basic ${hash}`
};
const config = {
headers
};
axios.get('http://localhost:9898/api/Contact/1', config);
I was looking back at the similar post I referenced earlier How to configure CORS in a Spring Boot + Spring Security application?
and I tried out the 4th most updated answer by user Soroosh Khodami Mar 11, 2021 and used their SecurityConfig.
#Override
protected void configure(HttpSecurity http) throws Exception {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
// You can customize the following part based on your project, it's only a sample
http.authorizeRequests().antMatchers("/**").permitAll().anyRequest()
.authenticated().and().csrf().disable().cors().configurationSource(request -> corsConfiguration);
}
My previous config was missing:
setAllowedHeaders(Listof("Authorization",..))
setAllowCredentials(true)
setExposedHeaders(Authorization)
this then lead me to a secondary issed which was caused by setting the header in my restcontroller get by id method.
response.setHeader("Access-Control-Allow-Origin", "**");
I got an error saying this was not allowed so then I changed it to "/**" and it still complained so I just commented it out and it worked. So if a tutorial suggests this (for me it was a youtube video about getting cors to work) I believe it is out of date/not best practice when you should set Access-Control-Allow-Origin in your Web Security Configuration.
I have a web project: .Net core API as a backend and React app as a frontend and everything is working fine with every browser except Mozilla private tab. When I run my react app in Mozilla private window this error occurs:
Cross-Origin Request Blocked: ... Reason: CORS request did not succeed
but if my cors policy is not correct how can other browsers connect my backend without any problem? (p.s Mozilla normal tab works fine as well)
Question: what is the problem and how can I fix it?
Here's a lot of same question :)
I'm facing same problem now.
After hundreds attempts i have semi-solition:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
//some other code here...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//some code...
app.UseRouting();
app.UseCors(x => x
.SetIsOriginAllowed(origin => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build());
app.UseAuthorization();
//other code
}
In react application:
export const loginUser = createAsyncThunk(
'user/loginUser',
async function(loginCredentials, {rejectWithValue}) {
try {
const response = await fetch(`https://localhost:5001/usr/loginuser`, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'Accept': 'text/plain',
},
body: JSON.stringify({loginCredentials})
});
if (!response.ok) {
throw new Error('Server Error!');
}
//other code
With this code i have situation when most of request are failed (seems like 'fetch canceled' in browser) but about 30% request are successfully. That's why i called it "semi"-solution.
Have no idea what's happening, because failed and normal requests are identical (headers and body).
I have a ReactJS and Java Spring Boot applications, both secured by Keycloak 11.0.2.
Keycloak is on port 8083, ReactJS on 3000 and Spring App is on 8085.
If I try to use the configuration provided below, I'm not able to hit my endpoint and I'm getting CORS error.
Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f52216b1-c235-4328-a2f9-d8448c3bf886&login=true&scope=openid. (Reason: CORS request did not succeed).
Chrome and Microsoft Edge:
Access to XMLHttpRequest at 'http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f57ffa9f-9679-4476-aa03-af86c3abb3c2&login=true&scope=openid' (redirected from 'http://localhost:8085/api/worker/create/product') 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.
xhr.js:184 GET http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/auth?response_type=code&client_id=event_sorcerer&redirect_uri=http%3A%2F%2Flocalhost%3A8085%2Fsso%2Flogin&state=f57ffa9f-9679-4476-aa03-af86c3abb3c2&login=true&scope=openid net::ERR_FAILED
When I try to hit my endpoint using Postman, I'm able to hit it. Below is my Keycloak Web Security configuration. The configuration uses application.properties file to configure Keycloak adapter.
When I set .authorizeRequests().antMatchers("/**").permitAll() in the config, I'm also able to hit my endpoint from browser and Postman.
#KeycloakConfiguration
public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authBuilder) throws Exception {
final KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider();
authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
authBuilder.authenticationProvider(authProvider);
}
/**
* Call superclass configure method and set the Keycloak configuration
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.csrf().disable()
.cors()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().anonymous()
//.and().authorizeRequests().antMatchers("/**").permitAll() //Uncomment for requests to be allowed!
.and().authorizeRequests().antMatchers("/api/admin/**").hasRole("ADMIN")
.and().authorizeRequests().antMatchers("/api/manager/**").hasAnyRole("MANAGER")
.and().authorizeRequests().antMatchers("/api/worker/**").hasRole("WORKER")
.anyRequest().authenticated();
}
/**
* Setup Auth Strategy. Don't add prefixes and suffixes to role strings
*/
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
/**
* Don't use keycloak.json. Instead, use application.yml properties.
* #return
*/
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
Here is a part of application.properties that sets up Keycloak:
spring:
jersey:
type: filter
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/token
jwk-set-uri: http://localhost:8083/auth/realms/sorcerer_realm/protocol/openid-connect/certs
keycloak:
realm: sorcerer_realm
auth-server-url: http://localhost:8083/auth/
ssl-required: external
resource: event_sorcerer
verify-token-audience: true
credentials:
secret-jwt:
secret: d84611c9-af79-423b-b12c-bfa7fec23e85
use-resource-role-mappings: true
confidential-port: 0
Here is my ReactJS application's Keycloak adapter setup:
const keycloakConfig = {
"clientId": "event_sorcerer_frontend",
"realm": "sorcerer_realm",
"auth-server-url": "http://localhost:8083/auth/",
"url": "http://localhost:8083/auth",
"ssl-required": "external",
"resource": "event_sorcerer",
"public-client": true,
"verify-token-audience": true,
"use-resource-role-mappings": true,
"confidential-port": 0
};
const keycloak = new Keycloak(keycloakConfig);
const initKeycloak = (onSuccessCallback, onFailureCallback) => {
let success = false;
timeoutWrapper(() => {
if(!success){
onFailureCallback();
}
});
keycloak.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',
pkceMethod: 'S256',
}).then((isAuthenticated) => {
success = true;
if(isAuthenticated) {
onSuccessCallback();
} else {
login();
}
});
}
Here is how I send the request to server:
export const Request = {
configureAxiosDefault: () => {
axios.defaults.baseURL = axiosDefaultConfiguration.baseUrl;
},
create: (data, endpoint, callback, errorCallback, finalCallback) => {
axios.post(serverEndpoint + endpoint, {
data: data,
headers: {
Authorization: `Bearer ${UserService.getToken()}`
}
})
.then(response => Utility.isEmpty(callback) ? defaultCallback(response) : callback(response))
.catch(response => Utility.isEmpty(errorCallback) ? defaultErrorCallback(response) : errorCallback(response))
.finally(response => {
if(!Utility.isEmpty(finalCallback)) {
finalCallback(response);
}
});
},
}
Here is my Keycloak configuration for frontend. Backend is the same, except the Access Type is confidential and the Root/Base url are different (not 3000 but 8085):
Here is my CORS configuration bean:
#Configuration
public class CORSConfiguration {
/**
* Setup CORS
* #return
*/
#Bean
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
config.setAllowedMethods(Arrays.asList(CorsConfiguration.ALL));
config.setAllowedHeaders(Arrays.asList(CorsConfiguration.ALL));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return source;
}
}
And lastly, here is my endpoint. URL resolves to api/worker/create/product
#RestController
#RequestMapping(ControllerEndpointsPrefix.WORKER + "/create")
public class CreationController {
#Autowired
private UserAgregate userAgregate;
#PostMapping("/product")
public boolean createProduct(#RequestBody CreateProductCommand command) {
return true;
}
}
I've managed to solve this.
The problem wasn't on the server side, but on client side.
configureAxiosDefault: () => {
axios.defaults.baseURL = axiosDefaultConfiguration.baseUrl;
axios.defaults.headers.Authorization = `Bearer ${UserService.getToken()}`
},
create: (data, endpoint, callback, errorCallback, finalCallback) => {
axios.post(serverEndpoint + endpoint, data)
.then(response => Utility.isEmpty(callback) ? defaultCallback(response) : callback(response))
.catch(response => Utility.isEmpty(errorCallback) ? defaultErrorCallback(response) : errorCallback(response))
.finally(response => {
if(!Utility.isEmpty(finalCallback)) {
finalCallback(response);
}
});
},
Server was unable to process the token, because I was sending it as a JSON object property. These changes made everything work OK.
So, CORS wasn't an issue at all. The issue was that request didn't contain an Authorization header.
There are a lot of StackOverflow questions regarding KeyCloak, and some of them incomplete and cryptic. I encountered a good amount of errors, because of OpenJDK, JDK versions etc.
If anyone needs explanations and solutions, working Spring Boot configuration is on my repository:
https://github.com/milosrs/EventSorcererBackend
We have a fully-working back-end login POST service, implemented using Spring Security, along with Spring Boot and Spring Session. A user needs to be logged-in in order to access other services. The login operation works, and so does the mechanism to restrict/allow access to the other services. This has been tested with Postman, which is "smart enough" to keep the session cookie on successive requests.
Now, we are trying to build the client on React. When using the browser's debug we can see the session cookie is sent in the response header without problems. We were trying to get the session cookie from the header and store it for successive requests, but it doesn't work. When investigating we learnt we are not meant to read the response header from the code, as explained here and here.
Our login operation should redirect to /customer/home, which works in Postman but not on our application. The behaviour we get with this is a 403 Forbidden, and the way we assess it is because the cookie is not set when redirecting, and hence the second operation (GET /customer/home) fails and returns 403. Is our understanding correct? However, the browser does not seem to keep the session cookie automatically. How are we supposed to maintain the session for subsequent requests if the cookie is not set automatically, and we are not supposed to read it manually? Are we supposed to NOT use cookies for this purpose, and issue authentication tokens instead?
We are obviously misunderstanding or missing something. Any pointers please?
Our WebSecurityConfigurerAdapter:
#EnableWebSecurity
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProviderService authenticationProviderService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/customer/register").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.permitAll()
.defaultSuccessUrl("/customer/home", false)
.and()
.logout()
.permitAll()
.and()
.httpBasic();
http.csrf().disable();
}
//[ . . . ]
}
Our client trying to do a POST:
const mw = store => next => action => {
if(action.type == 'SUBMIT_LOGIN_USER') {
var payload = {
username: action.user.username,
password: action.user.password
};
// Build formData object.
let formData = new FormData();
formData.append('username', action.user.username);
formData.append('password', action.user.password);
return fetch('http://192.168.0.34:8080/login', {
method: 'POST',
body: formData
}).then(
r => (r)
)
.then(function(response) {
console.log(document.cookie) //empty
console.log(response.headers.get('Set-Cookie')) //null
next(action)
})
.catch(function(err) {
console.info(err);
});
} else {
next(action)
}
}
Using JWT (JSON Web Tokens) is a great way to implement security on single page applications like React.
If you're going with the JWT approach it would be efficient to use a package like axios to for http requests from the client side. Axios allows you to easily add an authorization token to all requests without hassle.
Even if you're not using JWT try using axios to send authorization tokens efficiently.
I have some issues with CORS using React fetch and Spring Boot.
The React application runs on localhost:3000.
The Spring Boot backend runs on localhost:3001.
My problem is when I try to logging in using using fetch with the http://localhost:3001/login url the response in javascript does not contain the Authorization token.
The authentication on backend side works.
When I open the Chrome Inspector I can see the Authorization in the Network tab at the login request only it is missing in the javascript response.
The React fetch request look like the following: In the code the const userToken = response.headers.get('Authorization'); returns "null" string instead of the token.
return fetch("http://localhost:3001/login",{
method: 'post',
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
email,
password
})
})
.then(
response => {
if(response.ok) {
const userToken = response.headers.get('Authorization');
return true;
}
// Error handling
}
);
The Spring Boot Security config is like the following:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable().authorizeRequests()
.antMatchers(HttpMethod.POST, REGISTRATION_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(// Auth Filter)
.addFilter(// Another auth Filter)
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
Another thing. When I used proxy: "http://127.0.0.1:3001" in the package.json the login worked and the React code above could read Authorization header. But I don't want to use proxy.