1 package fr.tiogars.domaintemplate.domains.auth.services;
2
3 import java.nio.charset.StandardCharsets;
4 import java.time.Clock;
5 import java.time.Instant;
6 import java.util.Date;
7 import java.util.List;
8 import java.util.Optional;
9
10 import javax.crypto.SecretKey;
11
12 import org.springframework.beans.factory.annotation.Autowired;
13 import org.springframework.security.core.userdetails.UserDetails;
14 import org.springframework.stereotype.Service;
15
16 import fr.tiogars.domaintemplate.config.JwtProperties;
17 import io.jsonwebtoken.JwtException;
18 import io.jsonwebtoken.Jwts;
19 import io.jsonwebtoken.security.Keys;
20
21
22 @Service
23 public class JwtTokenService {
24
25 private final Clock clock;
26 private final JwtProperties properties;
27
28 @Autowired
29 public JwtTokenService(JwtProperties properties) {
30 this(properties, Clock.systemUTC());
31 }
32
33 JwtTokenService(JwtProperties properties, Clock clock) {
34 this.properties = properties;
35 this.clock = clock;
36 }
37
38 public String generateToken(UserDetails userDetails) {
39 Instant now = Instant.now(clock);
40 List<String> authorities = userDetails.getAuthorities().stream()
41 .map(authority -> authority.getAuthority())
42 .toList();
43 return Jwts.builder()
44 .subject(userDetails.getUsername())
45 .issuedAt(Date.from(now))
46 .expiration(Date.from(expiresAt(now)))
47 .claim("authorities", authorities)
48 .signWith(signingKey())
49 .compact();
50 }
51
52 public Optional<String> extractUsername(String token) {
53 try {
54 return Optional.ofNullable(Jwts.parser()
55 .verifyWith(signingKey())
56 .build()
57 .parseSignedClaims(token)
58 .getPayload()
59 .getSubject());
60 } catch (JwtException | IllegalArgumentException _) {
61 return Optional.empty();
62 }
63 }
64
65 public boolean isValid(String token, UserDetails userDetails) {
66 return extractUsername(token)
67 .map(username -> username.equals(userDetails.getUsername()))
68 .orElse(false);
69 }
70
71 public Instant expiresAt() {
72 return expiresAt(Instant.now(clock));
73 }
74
75 private Instant expiresAt(Instant now) {
76 return now.plusSeconds(properties.expirationSeconds());
77 }
78
79 private SecretKey signingKey() {
80 return Keys.hmacShaKeyFor(properties.secret().getBytes(StandardCharsets.UTF_8));
81 }
82 }