Am using Auth0 for my authentication service. I have a web application communicating with a springboot API. Am trying to authenticate access to my API resource using Auth0 jwt token. Below is my implementation.
My Auth0 JS web application
var options = {
allowAutocomplete: true,
autoclose: true,
container: 'login-auth',
theme: {
logo: 'http://palermoinn.com/wp-content/uploads/2015/12/pullman_palermoinn.png',
primaryColor: '#009688',
foregroundColor: "#009688",
labeledSubmitButton: false,
},
auth: {
audience: 'https://xxx.auth0.com/userinfo',
responseType: 'token id_token',
params: {
state: 'into',
scope: 'openid email profile roles'
}
},
redirectUri: window.location.href,
languageDictionary: {
title: "Log In"
}
};
// console.log(constants.CLIENT_ID + " or " + constants.VERIFY_URL + " or " + constants.TYPE_GET);
var lock = new Auth0Lock(
'CLIENT_ID',
'xxx.auth0.com',
options
);
if (token == null && profile == null) {
lock.show();
} else {
var HEADER = {
token: token,
timeStamp: new Date().getTime(),
access: profile
}
console.log(JSON.stringify(HEADER));
/**
* This request would first request a token from the Auth0 Server
* The token is returned and that token is used to access API resource
*/
network.call(constants.STATS_URL + '1', constants.TYPE_GET, {}, token);
// window.location.href = "dashboard.html";
}
From my springboot Web security configuration I implemented the following
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
configuration.setAllowCredentials(true);
configuration.addAllowedHeader("Authorization");
configuration.addAllowedHeader("cache-control");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
JwtWebSecurityConfigurer
.forRS256(AUTH_AUD, AUTH_ISSUER)
.configure(http)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/v1/clients/stats/{userId}").authenticated();
}
My question now is Springboot web config I designed won't auth my request with the token I passed in the header. It keeps giving me an 401 unauthorized response. What am I doing wrong?
Related
I'm trying to fetch data from post request in react, but I can't get nothing back, the response it's ok and save the data in the database, after that I need to return a token in react but I can't understand why It does't work.
I tried a lot ot cros but nothing change.
Here the request in react:
save(registerDTO) {
fetch('http://localhost:8080/api/auth/register',{ method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Access-Control-Allow-Credentials': true},body: JSON.stringify( registerDTO )})
.then(data => console.log(data))
.catch(error=>console.warn(error))
}
}
In the ispection on google chrome everything works but I can't see the response even on there
there isn't nothing in the response option.
This is my code on spring boot side:
#PostMapping("/register")
public ResponseEntity<Map<String,String>> registerHandler(#RequestBody RegisterDTO registerDTO) {
log.info("User: {}",registerDTO);
return ResponseEntity.ok(registerService.saveUser(registerDTO));
}
In postman everything work fine, I can't even get the error message in react.
I tried to add a lot of cors code:
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000","192.168.1.7:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","DELETE"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// #Bean
// public WebMvcConfigurer corsConfigurer() {
// return new WebMvcConfigurer() {
// #Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**").allowedOrigins("http://localhost:3000/**");
// }
// };
// }
// #Bean
// public CorsConfigurationSource corsConfigurationSource() {
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
// return source;
// }
and I added this annotation in the restcontroller:
#CrossOrigin(origins = "http://localhost:3000")
you missing:
.then(res=> res.json())
in your fetch code.
I'm trying to get a value from my rest api but for some reason it not letting me get it from an authorize user but when i set it permitAll() it does. I'm receiving a 403 error code.
Backend
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers(HttpMethod.GET,"/token/refresh/**").hasAnyAuthority("ROLE_USER");
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/user/**").hasAnyAuthority("ROLE_USER");
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/user/{username}/**").hasAnyAuthority("[ROLE_ADMIN]");
http.authorizeRequests().antMatchers(HttpMethod.POST,"/api/user/save/**").hasAnyAuthority("ROLE_ADMIN");
http.authorizeRequests().antMatchers("/api/login/**","/api/user/save/**","/api/role/addtouser/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.addFilter(customAuthenticationFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
http.httpBasic();
Front-End
here is the request is being send.
getUserId(username) {
this.http.get(`http://localhost:8080/api/user/${username}`).subscribe(
resp=>{
sessionStorage.setItem("id",resp.toString())
}
)
}
Interceptor
this is my interceptor i think it's adding it to the header
export class HttpInterceptorInterceptor implements HttpInterceptor {
constructor(private authrnticationService: AuthenticationServiceService, private router:Router) {}
intercept(req: HttpRequest<any>, next: HttpHandler){
let httpHeaders = new HttpHeaders();
let basicAuthHeaderString=this.authrnticationService.getAuthenticatedtoken();
let username= this.authrnticationService.getEmail();
if (!req.headers.has('Content-Type')) {
httpHeaders = httpHeaders.append('Content-Type', 'application/x-www-form-urlencoded')
}
if (basicAuthHeaderString) {
httpHeaders = httpHeaders.append('Authorization', basicAuthHeaderString)
}
const xhr=req.clone({
headers: httpHeaders
})
return next.handle(xhr).pipe(tap(() => {},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status !== 401) {
return;
}
sessionStorage.clear()
this.router.navigate(['login']);
}
}));
}
}
My goal is to authenticate the WebSocket CONNECT frame. I wish to be able to initialize Authentication user = ... by using X-Auth-Token.
TL:DR
I use the X-Auth-Token header. How the current authentication works:
User hit POST /login endpoint with Form Data username and password.
The response header will contain the key X-Auth-Token.
If you hit any REST endpoint with X-Auth-Token the server will recognize the user.
The issue is how to get Authentication from X-Auth-Token in the WebSocket CONNECT frame.
The current solution is to use JWT, however, one of the requirements for this project is a user should be able to invalidate the session. For JWT to be able to do that, the JWT should be a stateful, reference to this SO's the question
#Configuration
#EnableWebSocketMessageBroker
// see: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#websocket-stomp-authentication-token-based
#Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebSocketAuthenticationConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
String sessionId = accessor.getFirstNativeHeader("X-AUTH-TOKEN");
// Authentication user; // How to get Authentication from X-Auth-Token?
// accessor.setUser(user);
}
return message;
}
});
}
}
What I did:
I change Cookie-based authentication by letting the session be provided in a header.
// see: https://docs.spring.io/spring-session/docs/current/reference/html5/#httpsession-rest
#Configuration
// Override HttpSession's Filter, in this instance Spring Session is backed by Redis.
#EnableRedisHttpSession
public class HttpSessionConfig {
// Default connection configuration, to localhost:6739.
#Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
}
// Tell Spring to use HTTP headers, X-Auth-Token.
#Bean
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
}
logic to CONNECT and SUBSCRIBE
const X-Auth-Token = "" // get from the POST `/login` endpoint
const onConnectCallback = () => {
const destinations = ["/topic/channel/1", "/user/queue/messages"];
for (let i = 0; i < destinations.length; i++) {
stompClient.subscribe(destinations[i], (payload) => {
// receiveMessageCallback
});
}
};
const stompConfig = {
brokerURL: "ws://localhost:8080/chat",
connectHeaders: {
"X-Auth-Token": X_Auth_Token,
},
onConnect: onConnectCallback,
};
const stompClient = new StompJs.Client(stompConfig);
stompClient.activate();
Reference
I am worried that X-Auth-Token is not supported in WebSocket because based on SO's answer there is no API to retrieve session by id
I am using JWT and Spring security for developing a Forum Application. I am getting 403 error when accessing users' endpoints. It happened after the merge, previously everything working properly. The endpoint works properly from POSTMAN but the issue occurs when accessing from browser
Nothing in the code has been mixed up, now the Authorization header is not added to the request, but only in the endpoints for users, in other cases, it works. The bare token is stored at the local storage of the browser. What could be the reason for something like that?
Angular interceptor adding authorization header:
intercept(request: HttpRequest<any>, next: HttpHandler) {
const authHeader = AUTHORIZATION_HEADER;
const accessToken = this.authService.getAuthorization();
if (accessToken !== null) {
request = request.clone({
headers: request.headers.set(authHeader, accessToken),
withCredentials: false
});
}
return next.handle(request);
}
}
Angular Auth Service
login(userCredentials: UserCredentials): Observable<any> {
return this.http
.post<AccountInfo>(`${API_URL}/login`, userCredentials, { observe: 'response' })
.pipe(
tap((response: HttpResponse<AccountInfo>) => {
const token = response.headers.get(AUTHORIZATION_HEADER);
this.storeAuthorization(token);
const body = response.body;
this.storeAccountInfo(body);
})
);
}
getAuthorization(): string {
return localStorage.getItem(AUTHORIZATION_KEY);
}
private storeAuthorization(authToken: string) {
localStorage.setItem(AUTHORIZATION_KEY, authToken);
}
private storeAccountInfo(accountInfo: AccountInfo) {
localStorage.setItem(USERNAME_KEY, accountInfo.username);
localStorage.setItem(ROLE_KEY, accountInfo.role.toString());
}
Here is the git repo containing the source code
https://github.com/PatrykKleczkowski/Forum/tree/feature/improvments
I try to get token but it not works. Request work in postman, but when I try reproduce this in angular I getting:
My request in postman:
My request in angular:
getToken() {
const headers = new HttpHeaders();
headers.set('Authorization', 'Basic ZGV2Z2xhbi1jbGllbnQ6ZGV2Z2xhbi1zZWNyZXQ=');
headers.set('Content-Type', 'application/x-www-form-urlencoded');
const body = new URLSearchParams();
body.append('username', 'Alex123');
body.append('password', 'password');
body.append('grant_type', 'password');
this.http.post<AuthToken>('http://localhost:8080/oauth/token', body, {headers: headers})
.subscribe(
success => {
debugger
this.token = success.access_token;
}
);
}
my CORS configure, i thing all is good with it.:
#Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/api-docs/**").permitAll()
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/auth/token").permitAll()
}
#Bean
fun corsFilter(): FilterRegistrationBean<*> {
val source = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration()
config.allowCredentials = java.lang.Boolean.TRUE
config.addAllowedOrigin("*")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
source.registerCorsConfiguration("/**", config)
val bean = FilterRegistrationBean(CorsFilter(source))
bean.order = 0
return bean
}
It seems you have issues with CORS, please read the following article about to learn more about CORS.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
This answer should be an comment, but I'm unable to comment..