Skip to content
10 changes: 7 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/markbates/goth

go 1.18
go 1.23.0

toolchain go1.23.6

require (
github.com/go-chi/chi/v5 v5.1.0
Expand All @@ -13,15 +15,16 @@ require (
github.com/markbates/going v1.0.0
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c
github.com/stretchr/testify v1.9.0
golang.org/x/oauth2 v0.17.0
golang.org/x/oauth2 v0.27.0
)

require (
cloud.google.com/go/compute v1.20.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
Expand All @@ -34,6 +37,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
golang.org/x/crypto v0.21.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.32.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZN
cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand All @@ -13,6 +15,8 @@ github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
Expand Down Expand Up @@ -68,6 +72,7 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand All @@ -91,6 +96,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ=
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
60 changes: 35 additions & 25 deletions providers/instagram/instagram.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"

Expand All @@ -19,7 +20,7 @@ import (
var (
authURL = "https://api.instagram.com/oauth/authorize/"
tokenURL = "https://api.instagram.com/oauth/access_token"
endPointProfile = "https://api.instagram.com/v1/users/self/"
endPointProfile = "https://graph.instagram.com/me"
)

// New creates a new Instagram provider, and sets up important connection details.
Expand Down Expand Up @@ -76,64 +77,74 @@ func (p *Provider) BeginAuth(state string) (goth.Session, error) {
// FetchUser will go to Instagram and access basic information about the user.
func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
sess := session.(*Session)

user := goth.User{
AccessToken: sess.AccessToken,
Provider: p.Name(),
}

if user.AccessToken == "" {
// data is not yet retrieved since accessToken is still empty
log.Printf("[Instagram] Error: Missing access token for provider %s", p.Name())
return user, fmt.Errorf("%s cannot get user information without accessToken", p.providerName)
}

response, err := p.Client().Get(endPointProfile + "?access_token=" + url.QueryEscape(sess.AccessToken))
requestURL := endPointProfile + "?fields=id,username,account_type,media_count,profile_picture_url&access_token=" + url.QueryEscape(sess.AccessToken)

response, err := p.Client().Get(requestURL)
if err != nil {
log.Printf("[Instagram] Error making request: %v", err)
return user, err
}
defer response.Body.Close()

if response.StatusCode != http.StatusOK {
log.Printf("[Instagram] Received non-200 status code: %d", response.StatusCode)
return user, fmt.Errorf("%s responded with a %d trying to fetch user information", p.providerName, response.StatusCode)
}

bits, err := ioutil.ReadAll(response.Body)
if err != nil {
return user, err
}

err = json.NewDecoder(bytes.NewReader(bits)).Decode(&user.RawData)
if err != nil {
return user, err
}

err = userFromReader(bytes.NewReader(bits), &user)
return user, err
if err != nil {
return user, err
} else {
return user, nil
}
}

func userFromReader(reader io.Reader, user *goth.User) error {
u := struct {
Data struct {
ID string `json:"id"`
UserName string `json:"username"`
FullName string `json:"full_name"`
ProfilePicture string `json:"profile_picture"`
Bio string `json:"bio"`
Website string `json:"website"`
Counts struct {
Media int `json:"media"`
Follows int `json:"follows"`
FollowedBy int `json:"followed_by"`
} `json:"counts"`
} `json:"data"`
ID string `json:"id"`
UserName string `json:"username"`
AccountType string `json:"account_type"`
MediaCount int64 `json:"media_count"`
Biography string `json:"biography"`
ProfileUrl string `json:"profile_picture_url"`
Name string `json:"name"`

// Add other fields as needed
}{}
err := json.NewDecoder(reader).Decode(&u)
if err != nil {
log.Printf("[Instagram] Error decoding user data: %v", err)
return err
}
user.UserID = u.Data.ID
user.Name = u.Data.FullName
user.NickName = u.Data.UserName
user.AvatarURL = u.Data.ProfilePicture
user.Description = u.Data.Bio
user.UserID = u.ID
user.NickName = u.UserName
user.Description = u.Biography
user.AvatarURL = u.ProfileUrl
user.Name = u.Name
user.AccountType = u.AccountType

// Set other fields as needed
return err
}

Expand All @@ -147,19 +158,18 @@ func newConfig(p *Provider, scopes []string) *oauth2.Config {
TokenURL: tokenURL,
},
Scopes: []string{
"basic",
"instagram_business_basic",
},
}
defaultScopes := map[string]struct{}{
"basic": {},
"instagram_business_basic": {},
}

for _, scope := range scopes {
if _, exists := defaultScopes[scope]; !exists {
c.Scopes = append(c.Scopes, scope)
}
}

return c
}

Expand Down
1 change: 1 addition & 0 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ type User struct {
RefreshToken string
ExpiresAt time.Time
IDToken string
AccountType string
}