diff --git a/build.gradle b/build.gradle index f404fb4..973e6e1 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,10 @@ dependencies { implementation 'io.springfox:springfox-swagger-ui:2.9.2' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' + // fcm + implementation 'com.google.firebase:firebase-admin:9.2.0' +// implementation group: 'com.squareup.okhttp3', name: 'okhttp', version : '4.2.2' + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" } diff --git a/src/main/java/cmc/peerna/apiResponse/code/ResponseStatus.java b/src/main/java/cmc/peerna/apiResponse/code/ResponseStatus.java index 16354ca..2ee3276 100644 --- a/src/main/java/cmc/peerna/apiResponse/code/ResponseStatus.java +++ b/src/main/java/cmc/peerna/apiResponse/code/ResponseStatus.java @@ -1,5 +1,6 @@ package cmc.peerna.apiResponse.code; +import com.google.api.Http; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.http.HttpStatus; @@ -48,6 +49,7 @@ public enum ResponseStatus implements BaseCode { INVALID_ACCESS_TOKEN(UNAUTHORIZED, 4016, "액세스 토큰이 없거나 유효하지 않습니다."), + FCM_TOKEN_NOT_FOUND(BAD_REQUEST, 4017, "해당 유저의 FCM 토큰이 존재하지 않습니다."), WRONG_POST_TEST(BAD_REQUEST, 4101, "잘못된 POST 테스트 요청입니다."), @@ -58,8 +60,9 @@ public enum ResponseStatus implements BaseCode { // 500번대 에러 _INTERNAL_SERVER_ERROR(INTERNAL_SERVER_ERROR, 5000, "서버 에러, 관리자에게 문의 바랍니다."), - FEIGN_CLIENT_ERROR_500(HttpStatus.INTERNAL_SERVER_ERROR, 5001, "Inter server Error in feign client"); + FEIGN_CLIENT_ERROR_500(HttpStatus.INTERNAL_SERVER_ERROR, 5001, "Inter server Error in feign client"), + FCM_ACCESS_TOKEN_REQUEST_ERROR(INTERNAL_SERVER_ERROR, 5002, "서버 에러, FCM 서버에 AccessToken 요청할 때 에러 발생."); private final HttpStatus httpStatus; private final Integer code; diff --git a/src/main/java/cmc/peerna/apiResponse/exception/handler/NotificationException.java b/src/main/java/cmc/peerna/apiResponse/exception/handler/NotificationException.java new file mode 100644 index 0000000..155dab5 --- /dev/null +++ b/src/main/java/cmc/peerna/apiResponse/exception/handler/NotificationException.java @@ -0,0 +1,10 @@ +package cmc.peerna.apiResponse.exception.handler; + +import cmc.peerna.apiResponse.code.ResponseStatus; +import cmc.peerna.apiResponse.exception.GeneralException; + +public class NotificationException extends GeneralException { + public NotificationException(ResponseStatus code){ + super(code); + } +} diff --git a/src/main/java/cmc/peerna/domain/FcmToken.java b/src/main/java/cmc/peerna/domain/FcmToken.java new file mode 100644 index 0000000..cdb8430 --- /dev/null +++ b/src/main/java/cmc/peerna/domain/FcmToken.java @@ -0,0 +1,34 @@ +package cmc.peerna.domain; + +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +@Getter +@Builder +@Entity +@DynamicInsert +@DynamicUpdate +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class FcmToken { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Member member; + + private String token; + + public FcmToken(final String token, final Member member) { + this.token = token; + this.member = member; + } + + public void update(final String token) { + this.token = token; + } +} diff --git a/src/main/java/cmc/peerna/domain/PushAlarm.java b/src/main/java/cmc/peerna/domain/PushAlarm.java new file mode 100644 index 0000000..2160733 --- /dev/null +++ b/src/main/java/cmc/peerna/domain/PushAlarm.java @@ -0,0 +1,35 @@ +package cmc.peerna.domain; + +import cmc.peerna.domain.common.BaseEntity; +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +@Entity +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@DynamicInsert +@DynamicUpdate +public class PushAlarm extends BaseEntity { + + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + + private String body; + + private Boolean isConfirmed; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "owner_id") + private Member ownerMember; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member targetMember; + +} diff --git a/src/main/java/cmc/peerna/domain/enums/NotificationType.java b/src/main/java/cmc/peerna/domain/enums/NotificationType.java new file mode 100644 index 0000000..6f66caf --- /dev/null +++ b/src/main/java/cmc/peerna/domain/enums/NotificationType.java @@ -0,0 +1,13 @@ +package cmc.peerna.domain.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum NotificationType { + COMMENT("comment"), + EVENT("event"); + + private final String type; +} diff --git a/src/main/java/cmc/peerna/fcm/FcmInit.java b/src/main/java/cmc/peerna/fcm/FcmInit.java new file mode 100644 index 0000000..caa2c54 --- /dev/null +++ b/src/main/java/cmc/peerna/fcm/FcmInit.java @@ -0,0 +1,35 @@ +package cmc.peerna.fcm; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +import java.io.IOException; +import java.io.InputStream; + +@Configuration +public class FcmInit { + @Value("${firebase.admin-sdk}") + private String FIREBASE_KEY_PATH; + + @PostConstruct + public void firebaseMessaging() throws IOException { + ClassPathResource resource = new ClassPathResource(FIREBASE_KEY_PATH); + InputStream credentialStream = resource.getInputStream(); + try { + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(credentialStream)) + .build(); + FirebaseApp.initializeApp(options); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/cmc/peerna/fcm/dto/FcmAOSMessage.java b/src/main/java/cmc/peerna/fcm/dto/FcmAOSMessage.java new file mode 100644 index 0000000..8ee771a --- /dev/null +++ b/src/main/java/cmc/peerna/fcm/dto/FcmAOSMessage.java @@ -0,0 +1,35 @@ +package cmc.peerna.fcm.dto; + +import lombok.*; + +@Builder +@Getter +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class FcmAOSMessage { + + private boolean validateOnly; + private Message message; + + @Builder + @Getter + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + public static class Message{ + private Data data; + private String token; + } + + + @Builder + @Getter + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + public static class Data{ + private String title; + private String body; + private String targetView; + private String targetPK; + private String targetNotificationPK; + } +} \ No newline at end of file diff --git a/src/main/java/cmc/peerna/fcm/dto/FcmTokenRequest.java b/src/main/java/cmc/peerna/fcm/dto/FcmTokenRequest.java new file mode 100644 index 0000000..2eee904 --- /dev/null +++ b/src/main/java/cmc/peerna/fcm/dto/FcmTokenRequest.java @@ -0,0 +1,12 @@ +package cmc.peerna.fcm.dto; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public class FcmTokenRequest { + + private final String token; + private final Long memberId; +} \ No newline at end of file diff --git a/src/main/java/cmc/peerna/fcm/service/FcmService.java b/src/main/java/cmc/peerna/fcm/service/FcmService.java new file mode 100644 index 0000000..5b18231 --- /dev/null +++ b/src/main/java/cmc/peerna/fcm/service/FcmService.java @@ -0,0 +1,36 @@ +package cmc.peerna.fcm.service; + +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FcmService { + Logger logger = LoggerFactory.getLogger(FcmService.class); + + public void testFCMService(String fcmToken) + { + Message message = Message.builder() + .setToken(fcmToken) + .setNotification( + Notification.builder() + .setTitle("PeerNa FCM 테스트입니당") + .setBody("테스트 성공했나요??") + .build()) + .build(); + try { + String response = FirebaseMessaging.getInstance().send(message); + logger.info("the response of request FCM : {}",response); + }catch (FirebaseMessagingException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cmc/peerna/feign/FCMFeignClient.java b/src/main/java/cmc/peerna/feign/FCMFeignClient.java new file mode 100644 index 0000000..83f20ab --- /dev/null +++ b/src/main/java/cmc/peerna/feign/FCMFeignClient.java @@ -0,0 +1,18 @@ +package cmc.peerna.feign; + +import cmc.peerna.feign.config.FCMFeignConfig; +import cmc.peerna.feign.dto.FCMResponseDto; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@FeignClient(name = "FCMFeign", url = "https://fcm.googleapis.com", configuration = FCMFeignConfig.class) +@Component +public interface FCMFeignClient { + + @PostMapping("/v1/projects/peerna-68c2d/messages:send") + FCMResponseDto getFCMResponse(@RequestHeader("Authorization") String token, @RequestBody String fcmAOSMessage); +} diff --git a/src/main/java/cmc/peerna/feign/config/FCMFeignConfig.java b/src/main/java/cmc/peerna/feign/config/FCMFeignConfig.java new file mode 100644 index 0000000..2ffa0c9 --- /dev/null +++ b/src/main/java/cmc/peerna/feign/config/FCMFeignConfig.java @@ -0,0 +1,27 @@ +package cmc.peerna.feign.config; + +import cmc.peerna.feign.exception.FeignClientExceptionErrorDecoder; +import feign.Logger; +import feign.RequestInterceptor; +import feign.codec.ErrorDecoder; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; + +@RequiredArgsConstructor +public class FCMFeignConfig { + + @Bean + public RequestInterceptor requestInterceptor(){ + return template -> template.header("Content-Type", "application/json;charset=UTF-8"); + } + + @Bean + public ErrorDecoder errorDecoder() { + return new FeignClientExceptionErrorDecoder(); + } + + @Bean + Logger.Level feignLoggerLevel() { + return Logger.Level.FULL; + } +} diff --git a/src/main/java/cmc/peerna/feign/dto/FCMResponseDto.java b/src/main/java/cmc/peerna/feign/dto/FCMResponseDto.java new file mode 100644 index 0000000..f69b5f5 --- /dev/null +++ b/src/main/java/cmc/peerna/feign/dto/FCMResponseDto.java @@ -0,0 +1,10 @@ +package cmc.peerna.feign.dto; + +import lombok.*; + +@Getter +@Setter +@NoArgsConstructor +public class FCMResponseDto { + String name; +} diff --git a/src/main/java/cmc/peerna/repository/FcmTokenRepository.java b/src/main/java/cmc/peerna/repository/FcmTokenRepository.java new file mode 100644 index 0000000..d39828e --- /dev/null +++ b/src/main/java/cmc/peerna/repository/FcmTokenRepository.java @@ -0,0 +1,10 @@ +package cmc.peerna.repository; + +import cmc.peerna.domain.FcmToken; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface FcmTokenRepository extends JpaRepository { + Optional findByMemberId(Long memberId); +} diff --git a/src/main/java/cmc/peerna/repository/PushAlarmRepository.java b/src/main/java/cmc/peerna/repository/PushAlarmRepository.java new file mode 100644 index 0000000..d547cc1 --- /dev/null +++ b/src/main/java/cmc/peerna/repository/PushAlarmRepository.java @@ -0,0 +1,17 @@ +package cmc.peerna.repository; + +import cmc.peerna.domain.Member; +import cmc.peerna.domain.PushAlarm; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface PushAlarmRepository extends JpaRepository { + + Page findByOwnerMember(Member member, PageRequest pageRequest); + + + List findByTitleAndOwnerMemberAndIsConfirmedFalse(String title, Member member); +} diff --git a/src/main/java/cmc/peerna/service/RootService.java b/src/main/java/cmc/peerna/service/RootService.java index e3826b1..ecad512 100644 --- a/src/main/java/cmc/peerna/service/RootService.java +++ b/src/main/java/cmc/peerna/service/RootService.java @@ -4,6 +4,7 @@ import cmc.peerna.web.dto.responseDto.RootResponseDto; import cmc.peerna.web.dto.responseDto.TestResponseDto; +import java.io.IOException; import java.util.List; public interface RootService { diff --git a/src/main/java/cmc/peerna/service/serviceImpl/RootServiceImpl.java b/src/main/java/cmc/peerna/service/serviceImpl/RootServiceImpl.java index d7397cb..c27b6d5 100644 --- a/src/main/java/cmc/peerna/service/serviceImpl/RootServiceImpl.java +++ b/src/main/java/cmc/peerna/service/serviceImpl/RootServiceImpl.java @@ -8,12 +8,17 @@ import cmc.peerna.domain.enums.PeerCard; import cmc.peerna.domain.enums.PeerGrade; import cmc.peerna.domain.enums.TestType; +import cmc.peerna.fcm.service.FcmService; import cmc.peerna.repository.*; import cmc.peerna.service.RootService; import cmc.peerna.utils.TestResultCalculator; import cmc.peerna.web.dto.responseDto.MemberResponseDto; import cmc.peerna.web.dto.responseDto.RootResponseDto; import cmc.peerna.web.dto.responseDto.TestResponseDto; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingException; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -21,7 +26,9 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -36,7 +43,9 @@ public class RootServiceImpl implements RootService { private final PeerFeedbackRepository peerFeedbackRepository; private final PeerGradeResultRepository peerGradeResultRepository; private final PeerTestRepository peerTestRepository; + private final PushAlarmRepository pushAlarmRepository; private final TestResultCalculator testResultCalculator; + private final FcmService fcmService; @Value("${paging.size}") private Integer pageSize; @Override @@ -131,4 +140,5 @@ public RootResponseDto.AllFeedbackDto getFeedbackList(Member member, Integer pag return allFeedbackDto; } + } diff --git a/src/main/java/cmc/peerna/web/controller/RootController.java b/src/main/java/cmc/peerna/web/controller/RootController.java index 892bb7c..320b3f0 100644 --- a/src/main/java/cmc/peerna/web/controller/RootController.java +++ b/src/main/java/cmc/peerna/web/controller/RootController.java @@ -3,7 +3,10 @@ import cmc.peerna.apiResponse.code.ResponseStatus; import cmc.peerna.apiResponse.exception.handler.MemberException; import cmc.peerna.apiResponse.response.ResponseDto; +import cmc.peerna.converter.MemberConverter; +import cmc.peerna.fcm.service.FcmService; import cmc.peerna.service.MemberService; +import cmc.peerna.service.RootService; import cmc.peerna.web.dto.requestDto.RootRequestDto; import cmc.peerna.web.dto.responseDto.MemberResponseDto; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -13,6 +16,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.io.IOException; + @RestController @RequiredArgsConstructor @ApiResponses({ @@ -23,6 +28,8 @@ public class RootController { private final MemberService memberService; + private final FcmService fcmService; + private final RootService rootService; @GetMapping("/health") public String healthCheck() { @@ -51,4 +58,12 @@ public ResponseDto searchMember(@PathVariabl MemberResponseDto.MemberGetTestDto memberDto = memberService.findMember(memberId); return ResponseDto.of(memberDto); } + + @Operation(summary = "FCM 테스트 API", description = "테스트용") + @PostMapping("/test/fcm") + public ResponseDto testFCM(@RequestBody RootRequestDto.FCMTestDto fcmToken) throws IOException + { + fcmService.testFCMService(fcmToken.getFcmToken()); + return ResponseDto.of("FCM 테스트 성공!"); + } } diff --git a/src/main/java/cmc/peerna/web/dto/requestDto/RootRequestDto.java b/src/main/java/cmc/peerna/web/dto/requestDto/RootRequestDto.java index 75ed773..e858432 100644 --- a/src/main/java/cmc/peerna/web/dto/requestDto/RootRequestDto.java +++ b/src/main/java/cmc/peerna/web/dto/requestDto/RootRequestDto.java @@ -10,4 +10,12 @@ public class RootRequestDto { public static class PostTestDto{ private String body; } + + @Builder + @Getter + @AllArgsConstructor(access = AccessLevel.PROTECTED) + @NoArgsConstructor(access = AccessLevel.PROTECTED) + public static class FCMTestDto{ + String fcmToken; + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index dd4f4df..8f3e9c9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -70,3 +70,6 @@ web: paging: size : 10 + +firebase: + admin-sdk: firebase-adminsdk-key.json diff --git a/src/main/resources/firebase-adminsdk-key.json b/src/main/resources/firebase-adminsdk-key.json new file mode 100644 index 0000000..d02256c --- /dev/null +++ b/src/main/resources/firebase-adminsdk-key.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "peerna-68c2d", + "private_key_id": "ec9da851aa94f029adef064995e0a191e419fa90", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDNcNzIDbbv8J38\nEtpicqz+k9KW5q4m+VrlSmE/dzPwnoAF68nP5YlFp7oA82HXrOX3VqkcMDjqr2Ee\n5bPrWNSIvILSIsuUMxCZFqodTFaG27L0bB6LTCm3Je6bquAAOI3vSTvfGWQs680w\nFe6yDWTjl1qMl/GpDplz+jMOzaS5OdW+OiNcvfsdIXv17Y4o0KxZciXS95BwdXgx\nxYB4RlneGdZbnYevSj6X8bacBmplTha3IVuegenXkVeWhZCm97CH4dEkKTwcKRNX\nmaOmzysMgKqhuEmYejqV7xMVHfE4tEFokBhqlWvT8RGHSsJSDGdQhZ39dHzS9Bc3\nfslCBQBFAgMBAAECggEABPqOezGr5Io4Be8eCEM/soa6FIqgH1UtMP/ZtfxJT7RD\npYEWmbl2F3BOZ23+icfIpfMdc4+unW9lIubNsq8rLWomIHoT5XJMXW1pb37VXPzP\njDFflyAgJa5fZznfplm4hNtJPmmi3hzT0u3BJGMDNinJmb0n7+Eo8mDWom3050E2\nsQtr/TjzqdIjWjXLlCSxdaZTrsNrGmGuQUdr9XZFn0Br1UjlGdRS5YRz6K7NwPOy\nAkrbyc1rD63jjLGWJLXnzjhxTSV1KtMa7zvFIFG1a0YNN3WglUJmR6AfZvoL2QR/\nC5JzO3LTCrIyDre29EvhsjCROqLr7NkN7UdYItvyyQKBgQDpm5GXuFPLRwT5EWiV\nXvQNIqDEj0fID4zABfo9AfNyc05nmKhNvrFrzv6IP/p4UYKJ3hqXEqCib7d7UE8m\ntt/sdJEZTIlkDuSXY0Jy2VUfqvXEMKg/6I/x2Tls8RK58kQXIw21II8vAnMeZLvU\nfJwAZR5JnaK4MkeR/9I6d0KWGQKBgQDhIh3CyLselghV3cQmSuLFR1+mzPVlM8Wu\nJNWpbfxVtAuw5O5QWTeiLGJekmlxQBarCAhoKYZQDbeScFcUbB2lgsYtXwRpjiFY\nPOu+d/7SSNiNTia3tAc11ZZ+6rYEsYeRItC24RWsJxUjtKChrDPWpg1cpHWZ83w9\n66wrJdCJDQKBgG8RFvSyn6xbNMMSgs3Z2mDQYO1zTeaRdhLqBKKy5cM5jUJ18zcb\nfhFK1fuDp5tC7bSM08mWAqeYQ/0uHqPCeM5cUYxctknLRuWvPK2MJQusZbMEi0nv\nUVjkNYhVSdj8lWEGuoKuW0U3ffIqZJ9PK4CIkxDfELlQtnR008gWYaMpAoGAWO5B\nE1B3mf1qDYEsmnO6YHNxNVKBHRj2XXPvcp4frzsP4zCLcvHLKCSgNvte632FdsoV\niA/fHoBMo2v8+fQ7QcYGwqVl+MxMH67w8Kw13Jsp76ePY8GZl4pniHruq6v1AT/f\ncl43UWme0Bvp1/NOBtxRKudMDSRBT7RoriKh3YECgYAKncKC3C/y6RkNcLIkKLwF\nI5Bb7STKBQ96504kLN4Vd1cmnyhlBwPwoTO+BRvmbgJ1xa9hMssFHZoIu0UeRWM1\nAjbjMBfoUtZ7Axq2AoCAFZMEEn/0gscSUlpaJ5ro7nI+g2KROavJ5duoYVZfawi6\n1b/u+15n0u5SaD74GWZG8g==\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-m9f35@peerna-68c2d.iam.gserviceaccount.com", + "client_id": "102007965304250253664", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-m9f35%40peerna-68c2d.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +}