I don’t how to fix this, when I try to login in my project of angular, my backend send me this:
io.jsonwebtoken.ExpiredJwtException: JWT expired at 2024-05-06T13:45:41Z. Current time: 2024-05-07T17:36:16Z, a difference of 100235607 milliseconds. Allowed clock skew: 0 milliseconds.
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:427) ~[jjwt-impl-0.11.5.jar:0.11.5]
at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:529) ~[jjwt-impl-0.11.5.jar:0.11.5]
at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:589) ~[jjwt-impl-0.11.5.jar:0.11.5]
at io.jsonwebtoken.impl.ImmutableJwtParser.parseClaimsJws(ImmutableJwtParser.java:173) ~[jjwt-impl-0.11.5.jar:0.11.5]
at com.backend.floristeria.jwt.JwtService.getAllClaims(JwtService.java:71) ~[classes/:na]
at com.backend.floristeria.jwt.JwtService.getClaim(JwtService.java:76) ~[classes/:na]
at com.backend.floristeria.jwt.JwtService.getUsernameFromToken(JwtService.java:47) ~[classes/:na]
at com.backend.floristeria.jwt.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:38) ~[classes/:na]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) ~[spring-security-web-6.2.4.jar:6.2.4]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:195) ~[spring-webmvc-6.1.6.jar:6.1.6]
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:230) ~[spring-security-config-6.2.4.jar:6.2.4]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268) ~[spring-web-6.1.6.jar:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.6.jar:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.6.jar:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.20.jar:10.1.20]
at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
And in the browser this:
login.component.ts:38
POST http://localhost:8080/auth/login 403 (Forbidden)
error-interceptor.service.ts:14 HttpErrorResponse {headers: HttpHeaders, status: 403, statusText: 'OK', url: 'http://localhost:8080/auth/login', ok: false, …}
login.service.ts:49 Backend retornó el código de estado HttpErrorResponse {headers: HttpHeaders, status: 403, statusText: 'OK', url: 'http://localhost:8080/auth/login', ok: false, …}
login.component.ts:52 Error: Algo falló. Por favor intente nuevamente.
at login.service.ts:51:28
at Observable.init [as _subscribe] (throwError.js:5:51)
at Observable._trySubscribe (Observable.js:37:25)
at Observable.js:31:30
at errorContext (errorContext.js:19:9)
at Observable.subscribe (Observable.js:22:21)
at catchError.js:14:31
at OperatorSubscriber._error (OperatorSubscriber.js:23:21)
at OperatorSubscriber.error (Subscriber.js:40:18)
at OperatorSubscriber._error (Subscriber.js:64:30)
This is my JwtService:
package com.backend.floristeria.jwt;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.ExpiredJwtException;
@Service
public class JwtService {
private static final String SECRET_KEY="h4ourtgwrt3h4t3ubtwh0fh3h2roih20hr2h34rv0h230rhfh34fh4h";
public String getToken(UserDetails user) {
return getToken(new HashMap<>(), user);
}
private String getToken(Map<String,Object> extraClaims, UserDetails user) {
System.out.println("Tiempo actual del servidor: " + new Date());
System.out.println("Fecha de expiración del token: " + new Date(System.currentTimeMillis() + 1000 * 60 * 24));
return Jwts
.builder()
.setClaims(extraClaims)
.setSubject(user.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis()+1000*60*30))
.signWith(getKey(), SignatureAlgorithm.HS256)
.compact();
}
private Key getKey() {
byte[] keyBytes=Decoders.BASE64.decode(SECRET_KEY);
return Keys.hmacShaKeyFor(keyBytes);
}
public String getUsernameFromToken(String token) {
return getClaim(token, Claims::getSubject);
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
boolean isValid = false;
try {
if (username.equals(userDetails.getUsername())) {
isValid = !isTokenExpired(token);
}
} catch (ExpiredJwtException e) {
System.err.println("Token expired");
} catch (Exception e) {
System.err.println("Some other exception in JWT parsing");
}
return isValid;
}
private Claims getAllClaims(String token){
return Jwts
.parserBuilder()
.setSigningKey(getKey())
.build()
.parseClaimsJws(token)
.getBody();
}
public <T> T getClaim(String token, Function<Claims,T> claimsResolver){
final Claims claims=getAllClaims(token);
return claimsResolver.apply(claims);
}
private Date getExpiration(String token){
return getClaim(token, Claims::getExpiration);
}
private boolean isTokenExpired(String token){
return getExpiration(token).before(new Date());
}
}
My JwtAuthenticationFilter:
package com.backend.floristeria.jwt;
import java.io.IOException;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter{
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws IOException, ServletException {
final String token = getTokenFromRequest(request);
final String username;
if (token==null) {
filterChain.doFilter(request, response);
return;
}
username = jwtService.getUsernameFromToken(token);
if (username!=null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(token, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username,null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request,response);
}
private String getTokenFromRequest(HttpServletRequest request) {
final String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(authHeader) && authHeader.startsWith("Bearer ")) {
return authHeader.substring(7);
}
return null;
}
}
And some codes of angular:
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError, catchError, BehaviorSubject , tap, map} from 'rxjs';
import { environment } from 'src/environments/environments';
import { Login } from '../interfaces/login';
import { Usuario } from '../interfaces/usuario';
import { UsuarioService } from './usuario.service';
@Injectable({
providedIn: 'root'
})
export class LoginService {
currentUserLoginOn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
currentUserData: BehaviorSubject<String> =new BehaviorSubject<String>("");
constructor(private http: HttpClient) {
this.currentUserLoginOn=new BehaviorSubject<boolean>(sessionStorage.getItem("token")!=null);
this.currentUserData=new BehaviorSubject<String>(sessionStorage.getItem("token") || "");
}
login(credentials:Login):Observable<any>{
console.log("Tiempo actual del cliente: " + new Date());
return this.http.post<any>(environment.urlHost+"/auth/login",credentials).pipe(
tap(()=>{console.log("Entro?");
}),
tap( (userData) => {
console.log("hola");
sessionStorage.setItem("token", userData.token);
this.currentUserData.next(userData.token);
this.currentUserLoginOn.next(true);
}),
map((userData)=> userData.token),
catchError(this.handleError)
);
}
logout():void{
sessionStorage.removeItem("token");
this.currentUserLoginOn.next(false);
}
private handleError(error:HttpErrorResponse){
if(error.status===0){
console.error('Se ha producio un error ', error.error);
}
else{
console.error('Backend retornó el código de estado ', error);
}
return throwError(()=> new Error('Algo falló. Por favor intente nuevamente.'));
}
get userData():Observable<String>{
return this.currentUserData.asObservable();
}
get userLoginOn(): Observable<boolean>{
return this.currentUserLoginOn.asObservable();
}
get userToken():String{
return this.currentUserData.value;
}
}
import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Login } from 'src/app/interfaces/login';
import { LoginService } from 'src/app/services/login.service';
import { UsuarioService } from '../services/usuario.service';
@Component({
selector: 'app-login-page',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
loginError:string="";
loginForm=this.formBuilder.group({
username:['',[Validators.required,Validators.email]],
password: ['',Validators.required],
})
constructor(private formBuilder:FormBuilder, private router:Router, private loginService: LoginService, private userService: UsuarioService) { }
ngOnInit(): void {
}
get email(){
return this.loginForm.controls.username;
}
get password()
{
return this.loginForm.controls.password;
}
login() {
if (this.loginForm.valid) {
this.loginError = "";
console.log(this.loginForm.value);
this.loginService.login(this.loginForm.value as Login).subscribe({
next: (userData) => {
console.log(userData);
const username:string | null | undefined= this.loginForm.value.username; // Obtener solo el nombre de usuario
this.userService.obtenerUsuarioLogin(username).subscribe(
(user) =>{
console.log(user);
localStorage.setItem("id",(user.id).toString());
localStorage.setItem("username",user.username);
localStorage.setItem("role",user.role);
}
);
},
error: (errorData) => {
console.error(errorData);
this.loginError = errorData;
},
complete: () => {
this.router.navigateByUrl('/');
this.loginForm.reset();
}
});
} else {
this.loginForm.markAllAsTouched();
alert("Error al ingresar los datos.");
}
}
}
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { LoginService } from './login.service';
@Injectable({
providedIn: 'root'
})
export class JwtInterceptorService implements HttpInterceptor{
constructor(private loginService:LoginService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let token:String=this.loginService.userToken;
if (token!=""){
req=req.clone(
{
setHeaders: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
'Authorization': `Bearer ${token}`
}
}
)
}
return next.handle(req);
}
}
I try to change the time of the JWT expired but nothing.
Later I try this here:
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
boolean isValid = false;
try {
if (username.equals(userDetails.getUsername())) {
isValid = !isTokenExpired(token);
}
} catch (ExpiredJwtException e) {
System.err.println("Token expired");
} catch (Exception e) {
System.err.println("Some other exception in JWT parsing");
}
return isValid;
}
To see if i have another error and i try to watch videos in youtube and solutions in internet but nothing too.
New contributor
Francisco Jiménez Jiménez is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.