github.com/ngocphuongnb/tetua@v0.0.7-alpha/packages/auth/google.go (about) 1 package auth 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "strings" 10 11 "github.com/ngocphuongnb/tetua/app/auth" 12 "github.com/ngocphuongnb/tetua/app/config" 13 "github.com/ngocphuongnb/tetua/app/entities" 14 "github.com/ngocphuongnb/tetua/app/server" 15 "github.com/ngocphuongnb/tetua/app/utils" 16 "golang.org/x/oauth2" 17 "golang.org/x/oauth2/google" 18 ) 19 20 const oauthGoogleUrlAPI = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" 21 22 type GoogleUserResponse struct { 23 ID string `json:"id"` 24 Email string `json:"email"` 25 Name string `json:"name"` 26 Picture string `json:"picture"` 27 } 28 29 type GoogleAuthProvider struct { 30 config *oauth2.Config 31 } 32 33 func NewGoogle(cfg map[string]string) server.AuthProvider { 34 if cfg["client_id"] == "" || cfg["client_secret"] == "" { 35 panic("Github client id or secret is not set") 36 } 37 38 return &GoogleAuthProvider{ 39 config: &oauth2.Config{ 40 ClientID: cfg["client_id"], 41 ClientSecret: cfg["client_secret"], 42 Endpoint: google.Endpoint, 43 RedirectURL: utils.Url("/auth/google/callback"), 44 Scopes: []string{ 45 "https://www.googleapis.com/auth/userinfo.email", 46 "https://www.googleapis.com/auth/userinfo.profile", 47 }, 48 }, 49 } 50 } 51 52 func (g *GoogleAuthProvider) Name() string { 53 return "google" 54 } 55 56 func (g *GoogleAuthProvider) GetGoogleUserFromAccessCode(code string) (*GoogleUserResponse, error) { 57 token, err := g.config.Exchange(context.Background(), code) 58 if err != nil { 59 return nil, fmt.Errorf("code exchange wrong: %s", err.Error()) 60 } 61 response, err := http.Get(oauthGoogleUrlAPI + token.AccessToken) 62 if err != nil { 63 return nil, fmt.Errorf("failed getting user info: %s", err.Error()) 64 } 65 defer response.Body.Close() 66 body, err := ioutil.ReadAll(response.Body) 67 68 if err != nil { 69 return nil, fmt.Errorf("failed read response: %s", err.Error()) 70 } 71 72 userResponse := &GoogleUserResponse{} 73 if err := json.Unmarshal(body, userResponse); err != nil { 74 return nil, err 75 } 76 77 return userResponse, nil 78 } 79 80 func (g *GoogleAuthProvider) Login(c server.Context) error { 81 url := g.config.AuthCodeURL(c.Cookies(config.COOKIE_UUID)) 82 83 return c.Redirect(url) 84 } 85 86 func (g *GoogleAuthProvider) Callback(c server.Context) (u *entities.User, err error) { 87 if c.Query("state") != c.Cookies(config.COOKIE_UUID) { 88 return nil, fmt.Errorf("invalid oauth google state") 89 } 90 91 if c.Query("code") == "" { 92 return nil, fmt.Errorf("code is empty") 93 } 94 95 googleUser, err := g.GetGoogleUserFromAccessCode(c.Query("code")) 96 97 if err != nil { 98 return nil, err 99 } 100 101 return &entities.User{ 102 Provider: "google", 103 ProviderID: utils.SanitizePlainText(googleUser.ID), 104 Username: utils.SanitizePlainText(strings.Split(googleUser.Email, "@gmail")[0]), 105 Email: utils.SanitizePlainText(googleUser.Email), 106 ProviderAvatar: utils.SanitizePlainText(googleUser.Picture), 107 DisplayName: utils.SanitizePlainText(googleUser.Name), 108 URL: utils.SanitizePlainText(""), 109 ProviderUsername: utils.SanitizePlainText(googleUser.Email), 110 RoleIDs: []int{auth.ROLE_USER.ID}, 111 Active: config.Setting("auto_approve_user") == "yes", 112 }, nil 113 }