func (gm *GMServer) handleOAuthGoogle(
	tx *sql.Tx, code, redirectURL string,
	oauthCreds *OAuthCreds,
	endpoint oauth2.Endpoint,
	userID int,
) (uid int, googleTokenInfo *GoogleTokenInfo, err error) {
	if code == "" {
		return 0, nil, errors.Errorf("code is required")
	}

	if redirectURL == "" {
		return 0, nil, errors.Errorf("redirect_uri is required")
	}

	ctx := context.Background()
	conf := &oauth2.Config{
		ClientID:     oauthCreds.ClientID,
		ClientSecret: oauthCreds.ClientSecret,
		Scopes:       []string{"email"},
		Endpoint:     endpoint,
		RedirectURL:  redirectURL,
	}

	tok, err := conf.Exchange(ctx, code)
	if err != nil {
		return 0, nil, errors.Annotatef(err, "failed to exchange code for the token")
	}

	// Request token info by id_token

	idToken, ok := tok.Extra("id_token").(string)
	if !ok {
		return 0, nil, errors.Annotatef(err, "failed to get id_token data from the token")
	}

	qsVals := url.Values{}
	qsVals.Add("id_token", idToken)

	hc := &http.Client{Timeout: 10 * time.Second}
	tokenInfoURL := fmt.Sprintf(
		"https://www.googleapis.com/oauth2/v2/tokeninfo?%s", qsVals.Encode(),
	)
	tresp, err := hc.Get(tokenInfoURL)
	if err != nil {
		return 0, nil, errors.Annotatef(err, "could not verify token %q", idToken)
	}

	googleTokenInfo = &GoogleTokenInfo{}

	decoder := json.NewDecoder(tresp.Body)
	if err := decoder.Decode(googleTokenInfo); err != nil {
		return 0, nil, errors.Annotatef(err, "failed to decode google token info")
	}

	if tresp.StatusCode != http.StatusOK {
		return 0, nil, errors.Annotatef(err, "error getting token info: %q", *googleTokenInfo)
	}

	// Check if we have a record for that Google user
	ud, err := gm.si.GetUserByGoogleUserID(tx, googleTokenInfo.UserID)
	if err != nil {
		if errors.Cause(err) != storage.ErrUserDoesNotExist {
			// Some unexpected error
			return 0, nil, errors.Trace(err)
		}

		// We don't have a record for that Google user: let's create one
		glog.V(2).Infof("No record for the Google user %q, going to create..", googleTokenInfo.UserID)

		if userID == 0 {
			var err error
			glog.V(2).Infof("Creating a new GeekMarks user..")

			userID, err = gm.si.CreateUser(tx, &storage.UserData{
				Username: googleTokenInfo.Email,
				Email:    googleTokenInfo.Email,
			})
			if err != nil {
				return 0, nil, hh.MakeInternalServerError(err)
			}
		} else {
			glog.V(2).Infof("Using user id %d..", userID)
		}

		glog.V(2).Infof("Associating google user %q with GeekMarks user %d", googleTokenInfo.UserID, userID)
		if err := gm.si.CreateGoogleUser(
			tx, userID, googleTokenInfo.UserID, googleTokenInfo.Email,
		); err != nil {
			return 0, nil, errors.Trace(err)
		}
	} else {
		userID = ud.ID
		glog.V(2).Infof("Google user %q (email %q) belongs to user id %d",
			googleTokenInfo.UserID, googleTokenInfo.Email, userID,
		)
	}

	return userID, googleTokenInfo, nil
}
// userID can be 0: in this case, if there is no record for Google user,
// a new GeekMarks user will also be created.
//
// If, however, userID > 0, then a new Google user will be associated with
// the existing GeekMarks user.
userID can be 0: in this case, if there is no record for Google user,
a new GeekMarks user will also be created.

If, however, userID > 0, then a new Google user will be associated with
the existing GeekMarks user.
// userID can be 0 : in this case if there is no record for Google user // a new GeekMarks user will also be created . // // If however userID > 0 then a new Google user will be associated with // the existing GeekMarks user .
func (gm *GMServer) handleOAuthGoogle(
	tx *sql.Tx, code, redirectURL string,
	oauthCreds *OAuthCreds,
	endpoint oauth2.Endpoint,
	userID int,
) (uid int, googleTokenInfo *GoogleTokenInfo, err error) {
	if code == "" {
		return 0, nil, errors.Errorf("code is required")
	}
	if redirectURL == "" {
		return 0, nil, errors.Errorf("redirect_uri is required")
	}
	ctx := context.Background()
	conf := &oauth2.Config{
		ClientID:     oauthCreds.ClientID,
		ClientSecret: oauthCreds.ClientSecret,
		Scopes:       []string{"email"},
		Endpoint:     endpoint,
		RedirectURL:  redirectURL,
	}
	tok, err := conf.Exchange(ctx, code)
	if err != nil {
		return 0, nil, errors.Annotatef(err, "failed to exchange code for the token")
	}
	idToken, ok := tok.Extra("id_token").(string)
	if !ok {
		return 0, nil, errors.Annotatef(err, "failed to get id_token data from the token")
	}
	qsVals := url.Values{}
	qsVals.Add("id_token", idToken)
	hc := &http.Client{Timeout: 10 * time.Second}
	tokenInfoURL := fmt.Sprintf(
		"https://www.googleapis.com/oauth2/v2/tokeninfo?%s", qsVals.Encode(),
	)
	tresp, err := hc.Get(tokenInfoURL)
	if err != nil {
		return 0, nil, errors.Annotatef(err, "could not verify token %q", idToken)
	}
	googleTokenInfo = &GoogleTokenInfo{}
	decoder := json.NewDecoder(tresp.Body)
	if err := decoder.Decode(googleTokenInfo); err != nil {
		return 0, nil, errors.Annotatef(err, "failed to decode google token info")
	}
	if tresp.StatusCode != http.StatusOK {
		return 0, nil, errors.Annotatef(err, "error getting token info: %q", *googleTokenInfo)
	}
	ud, err := gm.si.GetUserByGoogleUserID(tx, googleTokenInfo.UserID)
	if err != nil {
		if errors.Cause(err) != storage.ErrUserDoesNotExist {
			return 0, nil, errors.Trace(err)
		}
		glog.V(2).Infof("No record for the Google user %q, going to create..", googleTokenInfo.UserID)
		if userID == 0 {
			var err error
			glog.V(2).Infof("Creating a new GeekMarks user..")
			userID, err = gm.si.CreateUser(tx, &storage.UserData{
				Username: googleTokenInfo.Email,
				Email:    googleTokenInfo.Email,
			})
			if err != nil {
				return 0, nil, hh.MakeInternalServerError(err)
			}
		} else {
			glog.V(2).Infof("Using user id %d..", userID)
		}
		glog.V(2).Infof("Associating google user %q with GeekMarks user %d", googleTokenInfo.UserID, userID)
		if err := gm.si.CreateGoogleUser(
			tx, userID, googleTokenInfo.UserID, googleTokenInfo.Email,
		); err != nil {
			return 0, nil, errors.Trace(err)
		}
	} else {
		userID = ud.ID
		glog.V(2).Infof("Google user %q (email %q) belongs to user id %d",
			googleTokenInfo.UserID, googleTokenInfo.Email, userID,
		)
	}
	return userID, googleTokenInfo, nil
}
func ( gm * GMServer ) handleOAuthGoogle ( tx * sql . Tx , code , redirectURL string , oauthCreds * OAuthCreds , endpoint oauth2 . Endpoint , userID int , ) ( uid int , googleTokenInfo * GoogleTokenInfo , err error ) { if code == " " { return 0 , nil , errors . Errorf ( " " ) } if redirectURL == " " { return 0 , nil , errors . Errorf ( " " ) } ctx := context . Background ( ) conf := & oauth2 . Config { ClientID : oauthCreds . ClientID , ClientSecret : oauthCreds . ClientSecret , Scopes : [ ] string { " " } , Endpoint : endpoint , RedirectURL : redirectURL , } tok , err := conf . Exchange ( ctx , code ) if err != nil { return 0 , nil , errors . Annotatef ( err , " " ) } idToken , ok := tok . Extra ( " " ) . ( string ) if ! ok { return 0 , nil , errors . Annotatef ( err , " " ) } qsVals := url . Values { } qsVals . Add ( " " , idToken ) hc := & http . Client { Timeout : 10 * time . Second } tokenInfoURL := fmt . Sprintf ( " " , qsVals . Encode ( ) , ) tresp , err := hc . Get ( tokenInfoURL ) if err != nil { return 0 , nil , errors . Annotatef ( err , " " , idToken ) } googleTokenInfo = & GoogleTokenInfo { } decoder := json . NewDecoder ( tresp . Body ) if err := decoder . Decode ( googleTokenInfo ) ; err != nil { return 0 , nil , errors . Annotatef ( err , " " ) } if tresp . StatusCode != http . StatusOK { return 0 , nil , errors . Annotatef ( err , " " , * googleTokenInfo ) } ud , err := gm . si . GetUserByGoogleUserID ( tx , googleTokenInfo . UserID ) if err != nil { if errors . Cause ( err ) != storage . ErrUserDoesNotExist { return 0 , nil , errors . Trace ( err ) } glog . V ( 2 ) . Infof ( " " , googleTokenInfo . UserID ) if userID == 0 { var err error glog . V ( 2 ) . Infof ( " " ) userID , err = gm . si . CreateUser ( tx , & storage . UserData { Username : googleTokenInfo . Email , Email : googleTokenInfo . Email , } ) if err != nil { return 0 , nil , hh . MakeInternalServerError ( err ) } } else { glog . V ( 2 ) . Infof ( " " , userID ) } glog . V ( 2 ) . Infof ( " " , googleTokenInfo . UserID , userID ) if err := gm . si . CreateGoogleUser ( tx , userID , googleTokenInfo . UserID , googleTokenInfo . Email , ) ; err != nil { return 0 , nil , errors . Trace ( err ) } } else { userID = ud . ID glog . V ( 2 ) . Infof ( " " , googleTokenInfo . UserID , googleTokenInfo . Email , userID , ) } return userID , googleTokenInfo , nil }
userID can be 0: in this case, if there is no record for Google user,
a new GeekMarks user will also be created.
userID can be 0 : in this case if there is no record for Google user a new GeekMarks user will also be created .
// Request token info by id_token // Check if we have a record for that Google user // Some unexpected error // We don't have a record for that Google user: let's create one