1
+ package com .baeldung .gcp .firebase .auth ;
2
+
3
+ import java .io .IOException ;
4
+ import java .util .Optional ;
5
+
6
+ import org .springframework .http .HttpStatus ;
7
+ import org .springframework .http .MediaType ;
8
+ import org .springframework .http .ProblemDetail ;
9
+ import org .springframework .security .authentication .UsernamePasswordAuthenticationToken ;
10
+ import org .springframework .security .core .context .SecurityContextHolder ;
11
+ import org .springframework .security .web .authentication .WebAuthenticationDetailsSource ;
12
+ import org .springframework .stereotype .Component ;
13
+ import org .springframework .web .filter .OncePerRequestFilter ;
14
+
15
+ import com .fasterxml .jackson .core .JsonProcessingException ;
16
+ import com .fasterxml .jackson .databind .ObjectMapper ;
17
+ import com .google .firebase .auth .FirebaseAuth ;
18
+ import com .google .firebase .auth .FirebaseAuthException ;
19
+ import com .google .firebase .auth .FirebaseToken ;
20
+
21
+ import jakarta .servlet .FilterChain ;
22
+ import jakarta .servlet .ServletException ;
23
+ import jakarta .servlet .http .HttpServletRequest ;
24
+ import jakarta .servlet .http .HttpServletResponse ;
25
+
26
+ @ Component
27
+ public class TokenAuthenticationFilter extends OncePerRequestFilter {
28
+
29
+ private static final String BEARER_PREFIX = "Bearer " ;
30
+ private static final String USER_ID_CLAIM = "user_id" ;
31
+ private static final String AUTHORIZATION_HEADER = "Authorization" ;
32
+
33
+ private final FirebaseAuth firebaseAuth ;
34
+ private final ObjectMapper objectMapper ;
35
+
36
+ public TokenAuthenticationFilter (FirebaseAuth firebaseAuth , ObjectMapper objectMapper ) {
37
+ this .firebaseAuth = firebaseAuth ;
38
+ this .objectMapper = objectMapper ;
39
+ }
40
+
41
+ @ Override
42
+ protected void doFilterInternal (HttpServletRequest request , HttpServletResponse response , FilterChain filterChain )
43
+ throws IOException , ServletException {
44
+ String authorizationHeader = request .getHeader (AUTHORIZATION_HEADER );
45
+
46
+ if (authorizationHeader != null && authorizationHeader .startsWith (BEARER_PREFIX )) {
47
+ String token = authorizationHeader .replace (BEARER_PREFIX , "" );
48
+ Optional <String > userId = extractUserIdFromToken (token );
49
+
50
+ if (userId .isPresent ()) {
51
+ var authentication = new UsernamePasswordAuthenticationToken (userId .get (), null , null );
52
+ authentication .setDetails (new WebAuthenticationDetailsSource ().buildDetails (request ));
53
+ SecurityContextHolder .getContext ().setAuthentication (authentication );
54
+ } else {
55
+ setAuthErrorDetails (response );
56
+ return ;
57
+ }
58
+ }
59
+ filterChain .doFilter (request , response );
60
+ }
61
+
62
+ private Optional <String > extractUserIdFromToken (String token ) {
63
+ try {
64
+ FirebaseToken firebaseToken = firebaseAuth .verifyIdToken (token , true );
65
+ String userId = String .valueOf (firebaseToken .getClaims ().get (USER_ID_CLAIM ));
66
+ return Optional .of (userId );
67
+ } catch (FirebaseAuthException exception ) {
68
+ return Optional .empty ();
69
+ }
70
+ }
71
+
72
+ private void setAuthErrorDetails (HttpServletResponse response ) throws JsonProcessingException , IOException {
73
+ HttpStatus unauthorized = HttpStatus .UNAUTHORIZED ;
74
+ response .setStatus (unauthorized .value ());
75
+ response .setContentType (MediaType .APPLICATION_JSON_VALUE );
76
+ ProblemDetail problemDetail = ProblemDetail .forStatusAndDetail (unauthorized , "Authentication failure: Token missing, invalid or expired" );
77
+ response .getWriter ().write (objectMapper .writeValueAsString (problemDetail ));
78
+ }
79
+
80
+ }
0 commit comments