From efcd7405dcfdb08480fd32462300095c5c061073 Mon Sep 17 00:00:00 2001 From: litsynp Date: Tue, 30 Jan 2024 17:12:09 +0900 Subject: [PATCH] feat: add API to generate FB custom token from Kakao --- cmd/server/handler/auth_handler.go | 39 +++++++++++++ cmd/server/main.go | 2 +- cmd/server/router.go | 1 + internal/domain/auth/view.go | 16 ++++++ internal/infra/kakao/client.go | 3 +- pkg/docs/docs.go | 90 ++++++++++++++++++++++++++++-- pkg/docs/swagger.json | 87 ++++++++++++++++++++++++++++- pkg/docs/swagger.yaml | 56 ++++++++++++++++++- 8 files changed, 283 insertions(+), 11 deletions(-) diff --git a/cmd/server/handler/auth_handler.go b/cmd/server/handler/auth_handler.go index e137528c..c2c0238f 100644 --- a/cmd/server/handler/auth_handler.go +++ b/cmd/server/handler/auth_handler.go @@ -78,3 +78,42 @@ func (h *authHandler) KakaoCallback(w http.ResponseWriter, r *http.Request) { PhotoURL: userProfile.Properties.ProfileImage, }) } + +// GenerateFBCustomTokenFromKakao godoc +// @Summary Kakao OAuth 토큰 기반 Firebase Custom Token 생성 API +// @Description 주어진 카카오 토큰으로 사용자 기본 정보를 검증하고 Firebase Custom Token을 발급합니다. +// @Tags auth +// @Accept json +// @Produce json +// @Param request body auth.GenerateFBCustomTokenRequest true "Firebase Custom Token 생성 요청" +// @Success 201 {object} auth.GenerateFBCustomTokenResponse +// @Failure 400 {object} commonviews.ErrorView +// @Router /auth/custom-tokens/kakao [post] +func (h *authHandler) GenerateFBCustomTokenFromKakao(w http.ResponseWriter, r *http.Request) { + var tokenRequest auth.GenerateFBCustomTokenRequest + if err := commonviews.ParseBody(w, r, &tokenRequest); err != nil { + return + } + + userProfile, err := h.kakaoClient.FetchUserProfile(tokenRequest.OAuthToken) + if err != nil { + commonviews.BadRequest(w, nil, "유효하지 않은 Kakao 인증 정보입니다.") + return + } + + customToken, err := h.authService.CustomToken(r.Context(), fmt.Sprintf("%d", userProfile.ID)) + if err != nil { + commonviews.InternalServerError(w, nil, err.Error()) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(auth.GenerateFBCustomTokenResponse{ + AuthToken: customToken, + FirebaseProviderType: user.FirebaseProviderTypeKakao, + FirebaseUID: fmt.Sprintf("%d", userProfile.ID), + Email: userProfile.KakaoAccount.Email, + PhotoURL: userProfile.Properties.ProfileImage, + }) +} diff --git a/cmd/server/main.go b/cmd/server/main.go index 8cbc8cc8..2af84efa 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -11,7 +11,7 @@ import ( ) // @title 이웃집멍냥 API 문서 -// @version 0.7.0 +// @version 0.8.0 // @description 이웃집멍냥 백엔드 API 문서입니다. // @termsOfService http://swagger.io/terms/ diff --git a/cmd/server/router.go b/cmd/server/router.go index 790c669d..778d2ce6 100644 --- a/cmd/server/router.go +++ b/cmd/server/router.go @@ -98,6 +98,7 @@ func NewRouter(app *firebaseinfra.FirebaseApp) *chi.Mux { r.Route("/auth", func(r chi.Router) { r.Get("/login/kakao", authHandler.KakaoLogin) r.Get("/callback/kakao", authHandler.KakaoCallback) + r.Post("/custom-tokens/kakao", authHandler.GenerateFBCustomTokenFromKakao) }) r.Route("/media", func(r chi.Router) { r.Get("/{id}", mediaHandler.FindMediaByID) diff --git a/internal/domain/auth/view.go b/internal/domain/auth/view.go index d610416c..cfa27d12 100644 --- a/internal/domain/auth/view.go +++ b/internal/domain/auth/view.go @@ -9,3 +9,19 @@ type KakaoCallbackResponse struct { Email string `json:"email"` PhotoURL string `json:"photoURL"` } + +// GenerateFBCustomTokenRequest는 OAuth 토큰 정보를 기반으로 Firebase Custom Token을 생성하기 위한 요청이다. +type GenerateFBCustomTokenRequest struct { + OAuthToken string `json:"oauthToken"` + OAuthID string `json:"oauthId"` + OAuthEmail string `json:"oauthEmail"` +} + +// GenerateFBCustomTokenResponse는 Firebase Custom Token을 생성하기 위한 응답이다. +type GenerateFBCustomTokenResponse struct { + AuthToken string `json:"authToken"` + FirebaseProviderType user.FirebaseProviderType `json:"fbProviderType"` + FirebaseUID string `json:"fbUid"` + Email string `json:"email"` + PhotoURL string `json:"photoURL"` +} diff --git a/internal/infra/kakao/client.go b/internal/infra/kakao/client.go index 2a2914e4..6d72c29b 100644 --- a/internal/infra/kakao/client.go +++ b/internal/infra/kakao/client.go @@ -2,6 +2,7 @@ package kakaoinfra import ( "encoding/json" + "fmt" "io" "net/http" "strings" @@ -70,7 +71,7 @@ func (kakaoClient *KakaoClient) FetchUserProfile(code string) (*kakaoUserProfile } if res.StatusCode != http.StatusOK { - return nil, err + return nil, fmt.Errorf("failed to fetch user profile from Kakao server") } body, err := io.ReadAll(res.Body) diff --git a/pkg/docs/docs.go b/pkg/docs/docs.go index cc6df7fc..464a9eff 100644 --- a/pkg/docs/docs.go +++ b/pkg/docs/docs.go @@ -1,4 +1,5 @@ -// Package docs Code generated by swaggo/swag. DO NOT EDIT +// Code generated by swaggo/swag. DO NOT EDIT. + package docs import "github.com/swaggo/swag" @@ -40,6 +41,46 @@ const docTemplate = `{ } } }, + "/auth/custom-tokens/kakao": { + "post": { + "description": "주어진 카카오 토큰으로 사용자 기본 정보를 검증하고 Firebase Custom Token을 발급합니다.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Kakao OAuth 토큰 기반 Firebase Custom Token 생성 API", + "parameters": [ + { + "description": "Firebase Custom Token 생성 요청", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/auth.GenerateFBCustomTokenRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/auth.GenerateFBCustomTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/commonviews.ErrorView" + } + } + } + } + }, "/auth/login/kakao": { "get": { "tags": [ @@ -603,6 +644,40 @@ const docTemplate = `{ } }, "definitions": { + "auth.GenerateFBCustomTokenRequest": { + "type": "object", + "properties": { + "oauthEmail": { + "type": "string" + }, + "oauthId": { + "type": "string" + }, + "oauthToken": { + "type": "string" + } + } + }, + "auth.GenerateFBCustomTokenResponse": { + "type": "object", + "properties": { + "authToken": { + "type": "string" + }, + "email": { + "type": "string" + }, + "fbProviderType": { + "$ref": "#/definitions/user.FirebaseProviderType" + }, + "fbUid": { + "type": "string" + }, + "photoURL": { + "type": "string" + } + } + }, "auth.KakaoCallbackResponse": { "type": "object", "properties": { @@ -623,6 +698,14 @@ const docTemplate = `{ } } }, + "commonviews.ErrorView": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, "commonviews.PaginatedView-pet_BreedView": { "type": "object", "properties": { @@ -1265,8 +1348,7 @@ const docTemplate = `{ "fbProviderType", "fbUid", "fullname", - "nickname", - "profileImageId" + "nickname" ], "properties": { "email": { @@ -1408,7 +1490,7 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "0.7.0", + Version: "0.8.0", Host: "", BasePath: "/api", Schemes: []string{}, diff --git a/pkg/docs/swagger.json b/pkg/docs/swagger.json index 0114c8db..a32aafda 100644 --- a/pkg/docs/swagger.json +++ b/pkg/docs/swagger.json @@ -12,7 +12,7 @@ "name": "Apache 2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0.html" }, - "version": "0.7.0" + "version": "0.8.0" }, "basePath": "/api", "paths": { @@ -33,6 +33,46 @@ } } }, + "/auth/custom-tokens/kakao": { + "post": { + "description": "주어진 카카오 토큰으로 사용자 기본 정보를 검증하고 Firebase Custom Token을 발급합니다.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Kakao OAuth 토큰 기반 Firebase Custom Token 생성 API", + "parameters": [ + { + "description": "Firebase Custom Token 생성 요청", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/auth.GenerateFBCustomTokenRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/auth.GenerateFBCustomTokenResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/commonviews.ErrorView" + } + } + } + } + }, "/auth/login/kakao": { "get": { "tags": [ @@ -596,6 +636,40 @@ } }, "definitions": { + "auth.GenerateFBCustomTokenRequest": { + "type": "object", + "properties": { + "oauthEmail": { + "type": "string" + }, + "oauthId": { + "type": "string" + }, + "oauthToken": { + "type": "string" + } + } + }, + "auth.GenerateFBCustomTokenResponse": { + "type": "object", + "properties": { + "authToken": { + "type": "string" + }, + "email": { + "type": "string" + }, + "fbProviderType": { + "$ref": "#/definitions/user.FirebaseProviderType" + }, + "fbUid": { + "type": "string" + }, + "photoURL": { + "type": "string" + } + } + }, "auth.KakaoCallbackResponse": { "type": "object", "properties": { @@ -616,6 +690,14 @@ } } }, + "commonviews.ErrorView": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, "commonviews.PaginatedView-pet_BreedView": { "type": "object", "properties": { @@ -1258,8 +1340,7 @@ "fbProviderType", "fbUid", "fullname", - "nickname", - "profileImageId" + "nickname" ], "properties": { "email": { diff --git a/pkg/docs/swagger.yaml b/pkg/docs/swagger.yaml index 943d1388..8055ce2c 100644 --- a/pkg/docs/swagger.yaml +++ b/pkg/docs/swagger.yaml @@ -1,5 +1,27 @@ basePath: /api definitions: + auth.GenerateFBCustomTokenRequest: + properties: + oauthEmail: + type: string + oauthId: + type: string + oauthToken: + type: string + type: object + auth.GenerateFBCustomTokenResponse: + properties: + authToken: + type: string + email: + type: string + fbProviderType: + $ref: '#/definitions/user.FirebaseProviderType' + fbUid: + type: string + photoURL: + type: string + type: object auth.KakaoCallbackResponse: properties: authToken: @@ -13,6 +35,11 @@ definitions: photoURL: type: string type: object + commonviews.ErrorView: + properties: + message: + type: string + type: object commonviews.PaginatedView-pet_BreedView: properties: items: @@ -453,7 +480,6 @@ definitions: - fbUid - fullname - nickname - - profileImageId type: object user.RegisterUserResponse: properties: @@ -535,7 +561,7 @@ info: url: http://www.apache.org/licenses/LICENSE-2.0.html termsOfService: http://swagger.io/terms/ title: 이웃집멍냥 API 문서 - version: 0.7.0 + version: 0.8.0 paths: /auth/callback/kakao: get: @@ -548,6 +574,32 @@ paths: summary: Kakao 회원가입 콜백 API tags: - auth + /auth/custom-tokens/kakao: + post: + consumes: + - application/json + description: 주어진 카카오 토큰으로 사용자 기본 정보를 검증하고 Firebase Custom Token을 발급합니다. + parameters: + - description: Firebase Custom Token 생성 요청 + in: body + name: request + required: true + schema: + $ref: '#/definitions/auth.GenerateFBCustomTokenRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/auth.GenerateFBCustomTokenResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/commonviews.ErrorView' + summary: Kakao OAuth 토큰 기반 Firebase Custom Token 생성 API + tags: + - auth /auth/login/kakao: get: responses: