package provider import ( "context" "strconv" "strings" "github.com/supabase/auth/internal/conf" "golang.org/x/oauth2" ) const ( defaultKakaoAuthBase = "kauth.kakao.com" defaultKakaoAPIBase = "kapi.kakao.com" IssuerKakao = "https://kauth.kakao.com" ) type kakaoProvider struct { *oauth2.Config APIHost string } type kakaoUser struct { ID int `json:"id"` Account struct { Profile struct { Name string `json:"nickname"` ProfileImageURL string `json:"profile_image_url"` } `json:"profile"` Email string `json:"email"` EmailValid bool `json:"is_email_valid"` EmailVerified bool `json:"is_email_verified"` } `json:"kakao_account"` } func (p kakaoProvider) GetOAuthToken(code string) (*oauth2.Token, error) { return p.Exchange(context.Background(), code) } func (p kakaoProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) { var u kakaoUser if err := makeRequest(ctx, tok, p.Config, p.APIHost+"/v2/user/me", &u); err != nil { return nil, err } data := &UserProvidedData{} if u.Account.Email != "" { data.Emails = []Email{ { Email: u.Account.Email, Verified: u.Account.EmailVerified && u.Account.EmailValid, Primary: true, }, } } data.Metadata = &Claims{ Issuer: p.APIHost, Subject: strconv.Itoa(u.ID), Name: u.Account.Profile.Name, PreferredUsername: u.Account.Profile.Name, // To be deprecated AvatarURL: u.Account.Profile.ProfileImageURL, FullName: u.Account.Profile.Name, ProviderId: strconv.Itoa(u.ID), UserNameKey: u.Account.Profile.Name, } return data, nil } func NewKakaoProvider(ext conf.OAuthProviderConfiguration, scopes string) (OAuthProvider, error) { if err := ext.ValidateOAuth(); err != nil { return nil, err } authHost := chooseHost(ext.URL, defaultKakaoAuthBase) apiHost := chooseHost(ext.URL, defaultKakaoAPIBase) oauthScopes := []string{ "account_email", "profile_image", "profile_nickname", } if scopes != "" { oauthScopes = append(oauthScopes, strings.Split(scopes, ",")...) } return &kakaoProvider{ Config: &oauth2.Config{ ClientID: ext.ClientID[0], ClientSecret: ext.Secret, Endpoint: oauth2.Endpoint{ AuthStyle: oauth2.AuthStyleInParams, AuthURL: authHost + "/oauth/authorize", TokenURL: authHost + "/oauth/token", }, RedirectURL: ext.RedirectURI, Scopes: oauthScopes, }, APIHost: apiHost, }, nil }