66import com .cloudmedia .identity .auth .social .GoogleIdentity ;
77import com .cloudmedia .identity .auth .social .GoogleTokenVerifier ;
88import com .cloudmedia .identity .error .ApiException ;
9+ import com .cloudmedia .identity .events .IdentityEventEnvelope ;
10+ import com .cloudmedia .identity .events .IdentityEventPublisher ;
11+ import com .cloudmedia .identity .events .UserCreatedPayload ;
12+ import com .cloudmedia .identity .events .UserUpdatedPayload ;
13+ import com .cloudmedia .identity .metrics .AuthMetrics ;
914import com .cloudmedia .identity .persistence .entity .OAuthAccountEntity ;
1015import com .cloudmedia .identity .persistence .entity .OAuthProvider ;
1116import com .cloudmedia .identity .persistence .entity .SessionEntity ;
1419import com .cloudmedia .identity .persistence .repository .OAuthAccountRepository ;
1520import com .cloudmedia .identity .persistence .repository .SessionRepository ;
1621import com .cloudmedia .identity .persistence .repository .UserRepository ;
22+ import java .time .Instant ;
1723import java .time .LocalDateTime ;
1824import java .time .ZoneOffset ;
1925import java .util .UUID ;
@@ -31,56 +37,73 @@ public class AuthSocialLoginService implements AuthSocialLoginUseCase {
3137 private final SessionRepository sessionRepository ;
3238 private final SessionLifecycleService sessionLifecycleService ;
3339 private final AuthTokenIssueService authTokenIssueService ;
40+ private final IdentityEventPublisher identityEventPublisher ;
41+ private final AuthMetrics authMetrics ;
3442
3543 public AuthSocialLoginService (AuthProperties authProperties , GoogleTokenVerifier googleTokenVerifier ,
3644 UserRepository userRepository , OAuthAccountRepository oAuthAccountRepository ,
3745 SessionRepository sessionRepository , SessionLifecycleService sessionLifecycleService ,
38- AuthTokenIssueService authTokenIssueService ) {
46+ AuthTokenIssueService authTokenIssueService , IdentityEventPublisher identityEventPublisher ,
47+ AuthMetrics authMetrics ) {
3948 this .authProperties = authProperties ;
4049 this .googleTokenVerifier = googleTokenVerifier ;
4150 this .userRepository = userRepository ;
4251 this .oAuthAccountRepository = oAuthAccountRepository ;
4352 this .sessionRepository = sessionRepository ;
4453 this .sessionLifecycleService = sessionLifecycleService ;
4554 this .authTokenIssueService = authTokenIssueService ;
55+ this .identityEventPublisher = identityEventPublisher ;
56+ this .authMetrics = authMetrics ;
4657 }
4758
4859 @ Override
4960 @ Transactional
5061 public RefreshResult socialLogin (SocialProvider provider , String providerToken , DeviceInfo deviceInfo ) {
51- if (provider != SocialProvider .GOOGLE ) {
52- throw new ApiException (HttpStatus .BAD_REQUEST , "SOCIAL_PROVIDER_UNSUPPORTED" ,
53- "Only GOOGLE provider is supported" , null );
54- }
62+ try {
63+ if (provider != SocialProvider .GOOGLE ) {
64+ throw new ApiException (HttpStatus .BAD_REQUEST , "SOCIAL_PROVIDER_UNSUPPORTED" ,
65+ "Only GOOGLE provider is supported" , null );
66+ }
5567
56- GoogleIdentity googleIdentity = googleTokenVerifier .verify (providerToken );
57- UserEntity user = resolveOrCreateUser (googleIdentity );
68+ GoogleIdentity googleIdentity = googleTokenVerifier .verify (providerToken );
69+ SocialResolution resolution = resolveOrCreateUser (googleIdentity );
5870
59- LocalDateTime now = LocalDateTime .now (ZoneOffset .UTC );
60- sessionLifecycleService .enforceSessionCap (user .getId (), authProperties .getMaxActiveSessions (), now );
61-
62- SessionEntity session = new SessionEntity ();
63- session .setId (UUID .randomUUID ().toString ());
64- session .setUser (user );
65- session .setDeviceId (deviceInfo != null ? deviceInfo .deviceId () : null );
66- session .setUserAgent (deviceInfo != null ? deviceInfo .userAgent () : null );
67- session .setIpAddress (deviceInfo != null ? deviceInfo .ipAddress () : null );
68- session .setCreatedAt (now );
69- session .setExpiresAt (now .plus (authProperties .getRefreshTokenTtl ()));
70-
71- SessionEntity savedSession = sessionRepository .save (session );
72- return authTokenIssueService .issueForSession (savedSession );
71+ LocalDateTime now = LocalDateTime .now (ZoneOffset .UTC );
72+ sessionLifecycleService .enforceSessionCap (resolution .user ().getId (), authProperties .getMaxActiveSessions (),
73+ now );
74+
75+ SessionEntity session = new SessionEntity ();
76+ session .setId (UUID .randomUUID ().toString ());
77+ session .setUser (resolution .user ());
78+ session .setDeviceId (deviceInfo != null ? deviceInfo .deviceId () : null );
79+ session .setUserAgent (deviceInfo != null ? deviceInfo .userAgent () : null );
80+ session .setIpAddress (deviceInfo != null ? deviceInfo .ipAddress () : null );
81+ session .setCreatedAt (now );
82+ session .setExpiresAt (now .plus (authProperties .getRefreshTokenTtl ()));
83+
84+ SessionEntity savedSession = sessionRepository .save (session );
85+ publishIdentityEvent (resolution );
86+ RefreshResult result = authTokenIssueService .issueForSession (savedSession );
87+ authMetrics .onSocialLoginSuccess ();
88+ return result ;
89+ } catch (ApiException exception ) {
90+ authMetrics .onSocialLoginFailure ();
91+ throw exception ;
92+ }
7393 }
7494
75- private UserEntity resolveOrCreateUser (GoogleIdentity identity ) {
95+ private SocialResolution resolveOrCreateUser (GoogleIdentity identity ) {
7696 return oAuthAccountRepository .findByProviderAndProviderSubject (OAuthProvider .GOOGLE , identity .subject ())
77- .map (OAuthAccountEntity ::getUser ).orElseGet (() -> createOrLinkUser (identity ));
97+ .map (account -> new SocialResolution (account .getUser (), false , false ))
98+ .orElseGet (() -> createOrLinkUser (identity ));
7899 }
79100
80- private UserEntity createOrLinkUser (GoogleIdentity identity ) {
101+ private SocialResolution createOrLinkUser (GoogleIdentity identity ) {
81102 LocalDateTime now = LocalDateTime .now (ZoneOffset .UTC );
103+ boolean [] createdNewUser = new boolean []{false };
82104
83105 UserEntity user = userRepository .findByEmail (identity .email ()).orElseGet (() -> {
106+ createdNewUser [0 ] = true ;
84107 UserEntity newUser = new UserEntity ();
85108 newUser .setId (UUID .randomUUID ().toString ());
86109 newUser .setEmail (identity .email ());
@@ -98,6 +121,25 @@ private UserEntity createOrLinkUser(GoogleIdentity identity) {
98121 account .setLinkedAt (now );
99122 oAuthAccountRepository .save (account );
100123
101- return user ;
124+ boolean linkedExistingUser = !createdNewUser [0 ];
125+ return new SocialResolution (user , createdNewUser [0 ], linkedExistingUser );
126+ }
127+
128+ private void publishIdentityEvent (SocialResolution resolution ) {
129+ if (resolution .createdUser ()) {
130+ identityEventPublisher .publish (new IdentityEventEnvelope (UUID .randomUUID ().toString (), "user.created" , 1 ,
131+ Instant .now (), "identity-service" , "user" , resolution .user ().getId (), null , new UserCreatedPayload (
132+ resolution .user ().getId (), resolution .user ().getEmail (), "google-social-login" )));
133+ return ;
134+ }
135+
136+ if (resolution .linkedExistingUser ()) {
137+ identityEventPublisher .publish (new IdentityEventEnvelope (UUID .randomUUID ().toString (), "user.updated" , 1 ,
138+ Instant .now (), "identity-service" , "user" , resolution .user ().getId (), null , new UserUpdatedPayload (
139+ resolution .user ().getId (), resolution .user ().getEmail (), "social-account-linked" )));
140+ }
141+ }
142+
143+ private record SocialResolution (UserEntity user , boolean createdUser , boolean linkedExistingUser ) {
102144 }
103145}
0 commit comments