diff --git a/gothic/gothic.go b/gothic/gothic.go index eddb3f69..7889c56d 100644 --- a/gothic/gothic.go +++ b/gothic/gothic.go @@ -366,9 +366,35 @@ func updateSessionValue(session *sessions.Session, key, value string) error { return nil } -func FetchUserInfoWithToken(token string) (goth.User, error) { +func FetchUserInfoWithToken(token string, providerName string, sessionValues interface{}) (goth.User, *goth.Session, error) { result := goth.User{} - return result, nil + if token == "" { + return result, nil, fmt.Errorf("cannot get user information without accessToken") + } + + provider, err := goth.GetProvider(providerName) + if err != nil { + return result, nil, err + } + + session, err := provider.CreateSession(sessionValues) + if err != nil { + return result, nil, err + } + + sess, err := provider.UnmarshalSession(session.Marshal()) + + if err != nil { + return result, nil, err + } + + user, err := provider.FetchUser(sess) + + if err != nil { + return result, nil, err + } + + return user, &session, nil } diff --git a/providers/google/google.go b/providers/google/google.go index a05a704c..68122036 100644 --- a/providers/google/google.go +++ b/providers/google/google.go @@ -15,7 +15,12 @@ import ( "golang.org/x/oauth2" ) -const endpointProfile string = "https://www.googleapis.com/oauth2/v2/userinfo" +const ( + endpointProfile string = "https://www.googleapis.com/oauth2/v2/userinfo" + authURL string = "https://accounts.google.com/o/oauth2/auth?access_type=offline" + tokenURL string = "https://accounts.google.com/o/oauth2/token" + idTokenProfile string = "https://www.googleapis.com/oauth2/v3/tokeninfo" +) // New creates a new Google provider, and sets up important connection details. // You should always call `google.New` to get a new Provider. Never try to create @@ -96,16 +101,34 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) { IDToken: sess.IDToken, } - if user.AccessToken == "" { + if user.AccessToken == "" && user.IDToken == "" { // Data is not yet retrieved, since accessToken is still empty. - return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName) + return user, fmt.Errorf("%s cannot get user information without accessToken AND idToken", p.providerName) + } + + var response *http.Response + var err error + // retrievedViaIDToken := false + + if user.IDToken != "" { + // retrievedViaIDToken = true + response, err = p.Client().Get(idTokenProfile + "?id_token=" + url.QueryEscape(sess.IDToken)) + if response.StatusCode == http.StatusBadRequest && len(sess.AccessToken) > 0 { + response, err = p.Client().Get(endpointProfile + "?access_token=" + url.QueryEscape(sess.AccessToken)) + // retrievedViaIDToken = false + } + + } else { + response, err = p.Client().Get(endpointProfile + "?access_token=" + url.QueryEscape(sess.AccessToken)) + } + + if response != nil { + defer response.Body.Close() } - response, err := p.Client().Get(endpointProfile + "?access_token=" + url.QueryEscape(sess.AccessToken)) if err != nil { return user, err } - defer response.Body.Close() if response.StatusCode != http.StatusOK { return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode) @@ -212,6 +235,5 @@ func (p *Provider) SetAccessType(at string) { } func (p *Provider) FetchUserWithToken(token string) (goth.User, error) { - //TODO: Implement this return goth.User{}, errors.New("not implemented") } diff --git a/providers/google/session.go b/providers/google/session.go index 42ad7fa6..e933f732 100644 --- a/providers/google/session.go +++ b/providers/google/session.go @@ -63,5 +63,24 @@ func (p *Provider) UnmarshalSession(data string) (goth.Session, error) { } func (p *Provider) CreateSession(sessionValue interface{}) (goth.Session, error) { - return &Session{}, errors.New("not implemented") + // First retrieve following keys with it's values from sessionValue + // - accessToken + // - expiresIn + // - clientID + + // Then create a new session with the retrieved values + sessStruct := sessionValue.(map[string]interface{}) + + accessToken := sessStruct["accessToken"].(string) + expiresIn := sessStruct["expiresIn"].(time.Time) + + session := &Session{ + AccessToken: accessToken, + IDToken: accessToken, + ExpiresAt: expiresIn, + } + + // ClientID = clientID + + return session, nil }