3535import java .util .List ;
3636import java .util .Optional ;
3737import java .util .UUID ;
38+ import java .util .stream .Stream ;
3839
3940@ Slf4j
4041@ Service
@@ -58,7 +59,16 @@ public GoogleLoginService(
5859 this .jwtTokenProvider = jwtTokenProvider ;
5960 this .userRepository = userRepository ;
6061 this .userAlarmSettingRepository = userAlarmSettingRepository ;
61- this .validClientIds = List .of (webClientId , appClientId );
62+ this .validClientIds = Stream .concat (
63+ Stream .of (webClientId ),
64+ Stream .of (appClientId .split ("," ))
65+ )
66+ .map (String ::trim )
67+ .filter (clientId -> !clientId .isBlank ())
68+ .toList ();
69+ log .info ("Configured Google OAuth audiences: {}" , validClientIds .stream ()
70+ .map (this ::maskClientId )
71+ .toList ());
6272 }
6373
6474
@@ -166,10 +176,52 @@ public GoogleIdToken.Payload verifyIdentityToken(String identityToken) throws Ex
166176 return payload ;
167177 } else {
168178 log .info ("Google identity credential is invalid" );
179+ logGoogleIdentityTokenClaims (identityToken );
169180 return null ;
170181 }
171182 }
172183
184+ private void logGoogleIdentityTokenClaims (String identityToken ) {
185+ try {
186+ GoogleIdToken parsedToken = GoogleIdToken .parse (
187+ GsonFactory .getDefaultInstance (),
188+ identityToken
189+ );
190+ GoogleIdToken .Payload payload = parsedToken .getPayload ();
191+ String audience = String .valueOf (payload .getAudience ());
192+ Long expirationTimeSeconds = payload .getExpirationTimeSeconds ();
193+ long nowSeconds = System .currentTimeMillis () / 1000 ;
194+ log .info (
195+ "Google identity token claims aud={}, azp={}, iss={}, exp={}, now={}, secondsUntilExp={}, audienceAllowed={}" ,
196+ maskClientId (audience ),
197+ payload .get ("azp" ),
198+ payload .getIssuer (),
199+ expirationTimeSeconds ,
200+ nowSeconds ,
201+ expirationTimeSeconds == null ? null : expirationTimeSeconds - nowSeconds ,
202+ validClientIds .contains (audience )
203+ );
204+ } catch (Exception e ) {
205+ log .info ("Google identity token claim parsing failed: {}" , e .getClass ().getSimpleName ());
206+ }
207+ }
208+
209+ private String maskClientId (String clientId ) {
210+ int separatorIndex = clientId .indexOf ('-' );
211+ if (separatorIndex < 0 ) {
212+ return "<invalid-client-id>" ;
213+ }
214+ String projectNumber = clientId .substring (0 , separatorIndex );
215+ String suffix = ".apps.googleusercontent.com" ;
216+ boolean hasGoogleSuffix = clientId .endsWith (suffix );
217+ String middle = clientId .substring (
218+ separatorIndex + 1 ,
219+ hasGoogleSuffix ? clientId .length () - suffix .length () : clientId .length ()
220+ );
221+ String visibleTail = middle .length () <= 4 ? middle : middle .substring (middle .length () - 4 );
222+ return projectNumber + "-..." + visibleTail + (hasGoogleSuffix ? suffix : "" );
223+ }
224+
173225 public boolean revokeToken (Long userId ) {
174226 User user = userRepository .findById (userId )
175227 .orElseThrow (() -> new IllegalArgumentException ("User not found with id: " + userId ));
0 commit comments