Skip to content

Commit

Permalink
feat: add API to generate FB custom token from Kakao
Browse files Browse the repository at this point in the history
  • Loading branch information
litsynp committed Feb 3, 2024
1 parent 9fda3d8 commit 8a0b69e
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 28 deletions.
44 changes: 41 additions & 3 deletions cmd/server/handler/auth_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net/http"

"github.com/go-chi/render"
app "github.com/pet-sitter/pets-next-door-api/api"
pnd "github.com/pet-sitter/pets-next-door-api/api"
"github.com/pet-sitter/pets-next-door-api/internal/configs"
"github.com/pet-sitter/pets-next-door-api/internal/domain/auth"
Expand Down Expand Up @@ -51,13 +50,13 @@ func (h *authHandler) KakaoCallback(w http.ResponseWriter, r *http.Request) {
code := pnd.ParseOptionalStringQuery(r, "code")
tokenView, err := h.kakaoClient.FetchAccessToken(*code)
if err != nil {
render.Render(w, r, app.ErrUnknown(err))
render.Render(w, r, pnd.ErrUnknown(err))
return
}

userProfile, err := h.kakaoClient.FetchUserProfile(tokenView.AccessToken)
if err != nil {
render.Render(w, r, app.ErrUnknown(err))
render.Render(w, r, pnd.ErrUnknown(err))
return
}

Expand All @@ -76,3 +75,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} pnd.AppError
// @Router /auth/custom-tokens/kakao [post]
func (h *authHandler) GenerateFBCustomTokenFromKakao(w http.ResponseWriter, r *http.Request) {
var tokenRequest auth.GenerateFBCustomTokenRequest
if err := pnd.ParseBody(r, &tokenRequest); err != nil {
render.Render(w, r, err)
return
}

userProfile, err2 := h.kakaoClient.FetchUserProfile(tokenRequest.OAuthToken)
if err2 != nil {
render.Render(w, nil, pnd.ErrBadRequest(fmt.Errorf("유효하지 않은 Kakao 인증 정보입니다")))
return
}

customToken, err := h.authService.CustomToken(r.Context(), fmt.Sprintf("%d", userProfile.ID))
if err != nil {
render.Render(w, r, err)
return
}

render.Status(r, http.StatusCreated)
render.JSON(w, r, auth.GenerateFBCustomTokenResponse{
AuthToken: *customToken,
FirebaseProviderType: user.FirebaseProviderTypeKakao,
FirebaseUID: fmt.Sprintf("%d", userProfile.ID),
Email: userProfile.KakaoAccount.Email,
PhotoURL: userProfile.Properties.ProfileImage,
})
}
2 changes: 1 addition & 1 deletion cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

// @title 이웃집멍냥 API 문서
// @version 0.7.0
// @version 0.8.0
// @description 이웃집멍냥 백엔드 API 문서입니다.
// @termsOfService http://swagger.io/terms/

Expand Down
1 change: 1 addition & 0 deletions cmd/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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)
Expand Down
14 changes: 14 additions & 0 deletions internal/domain/auth/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ type KakaoCallbackView struct {
Email string `json:"email"`
PhotoURL string `json:"photoURL"`
}

// GenerateFBCustomTokenRequest는 OAuth 토큰 정보를 기반으로 Firebase Custom Token을 생성하기 위한 요청이다.
type GenerateFBCustomTokenRequest struct {
OAuthToken string `json:"oauthToken"`
}

// 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"`
}
3 changes: 2 additions & 1 deletion internal/infra/kakao/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kakaoinfra

import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
Expand Down Expand Up @@ -70,7 +71,7 @@ func (kakaoClient *KakaoDefaultClient) FetchUserProfile(code string) (*kakaoUser
}

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)
Expand Down
121 changes: 113 additions & 8 deletions pkg/docs/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8a0b69e

Please sign in to comment.