I am trying to implement a token based authentication with spring boot and angular. The authentication token is exposed to HTTP response headers with a same name token. In angular I have a following request to my api in my service file:
login(username: string, password: string): Observable<any> {
return this.http.post(AUTH_API + 'login', {
username,
password
}, httpOptions);
}
And a following component ts method:
onSubmit(): void {
const { username, password } = this.form;
this.authService.login(username, password).subscribe({
next: data => {
console.log(data.headers.get('token'));
//this.tokenStorage.saveToken(data.accessToken);
this.tokenStorage.saveUser(data);
this.isLoginFailed = false;
this.isLoggedIn = true;
this.roles = this.tokenStorage.getUser().roles;
this.reloadPage();
},
error: err => {
// console.log( this.tokenStorage.getUser().roles);
console.log("ERR");
this.errorMessage = err.error.message;
this.isLoginFailed = true;
}
});
}
When I try to show the token header in console I am getting the following error: TypeError: Cannot read properties of null (reading 'headers') Here is my cors configuration from spring boot in security config class:
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
// source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
CorsConfiguration conf= new CorsConfiguration().applyPermitDefaultValues();
conf.setExposedHeaders(Arrays.asList("token"));
source.registerCorsConfiguration("/**", conf);
return source;
The token header is visible in a postman or a chrome consol, but not in angular front end. What am I missing? Http options
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new AuthenticationFilter(authenticationManager()))
.addFilter(new AuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
Angular http options
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
Headers
Request URL: http://localhost:8080/login
Request Method: POST
Status Code: 200
Remote Address: [::1]:8080
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: token
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Date: Sat, 29 Jan 2022 22:06:39 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
token: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0MTAiLCJleHAiOjE2NDM1MDU5OTl9.xtZxAU-TbpUmWFm_CuKS7iCHu-FiBs332cCVlxca6AwY4XOz-K7GJ4yB8PLLjk1JuXcgs1sbcVHeBto7iW7rpA
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Content-Length: 41
Content-Type: application/json
Host: localhost:8080
Origin: http://localhost:8081
Referer: http://localhost:8081/
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
You have to set the part that needs to be observed within the options:
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
observe: 'response'
};
return this.http.post(AUTH_API + 'login', {
username,
password
}, httpOptions);
That will give you the whole response so that your data parameter within the subscription callback will contain headers
and body
.