Skip to content

Commit

Permalink
Implement Facebook provider.
Browse files Browse the repository at this point in the history
Adds a simple implementation to connect with Facebook.

Signed-off-by: David Calavera <david.calavera@gmail.com>
  • Loading branch information
calavera committed Oct 4, 2017
1 parent a04e0cd commit a7424e1
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 0 deletions.
2 changes: 2 additions & 0 deletions api/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ func (a *API) Provider(ctx context.Context, name string) (provider.Provider, err
return provider.NewGitlabProvider(config.External.Gitlab)
case "google":
return provider.NewGoogleProvider(config.External.Google)
case "facebook":
return provider.NewFacebookProvider(config.External.Facebook)
default:
return nil, fmt.Errorf("Provider %s could not be found", name)
}
Expand Down
75 changes: 75 additions & 0 deletions api/provider/facebook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package provider

import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"errors"
"strings"

"github.com/netlify/gotrue/conf"
"golang.org/x/oauth2"
"golang.org/x/oauth2/facebook"
)

const profileURL = "https://graph.facebook.com/me?fields=email,first_name,last_name,name,picture"

type facebookProvider struct {
*oauth2.Config
}

type facebookUser struct {
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Alias string `json:"name"`
Avatar struct {
Data struct {
URL string `json:"url"`
} `json:"data"`
} `json:"picture"`
}

// NewFacebookProvider creates a Facebook account provider.
func NewFacebookProvider(ext conf.OAuthProviderConfiguration) (Provider, error) {
return &facebookProvider{
Config: &oauth2.Config{
ClientID: ext.ClientID,
ClientSecret: ext.Secret,
RedirectURL: ext.RedirectURI,
Endpoint: facebook.Endpoint,
Scopes: []string{"email"},
},
}, nil
}

func (p facebookProvider) GetOAuthToken(code string) (*oauth2.Token, error) {
return p.Exchange(oauth2.NoContext, code)
}

func (p facebookProvider) GetUserData(ctx context.Context, tok *oauth2.Token) (*UserProvidedData, error) {
hash := hmac.New(sha256.New, []byte(p.Config.ClientSecret))
hash.Write([]byte(tok.AccessToken))
appsecretProof := hex.EncodeToString(hash.Sum(nil))

var u facebookUser
url := profileURL + "&appsecret_proof=" + appsecretProof
if err := makeRequest(ctx, tok, p.Config, url, &u); err != nil {
return nil, err
}

if u.Email == "" {
return nil, errors.New("Unable to find email with Facebook provider")
}

return &UserProvidedData{
Metadata: map[string]string{
aliasKey: u.Alias,
nameKey: strings.TrimSpace(u.FirstName + " " + u.LastName),
avatarURLKey: u.Avatar.Data.URL,
},
Email: u.Email,
Verified: true,
}, nil
}
1 change: 1 addition & 0 deletions api/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
const (
avatarURLKey = "avatar_url"
nameKey = "full_name"
aliasKey = "slug"
)

type UserProvidedData struct {
Expand Down
1 change: 1 addition & 0 deletions conf/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type ExternalProviderConfiguration struct {
Github OAuthProviderConfiguration `json:"github"`
Gitlab OAuthProviderConfiguration `json:"gitlab"`
Google OAuthProviderConfiguration `json:"google"`
Facebook OAuthProviderConfiguration `json:"facebook"`
RedirectURL string `json:"redirect_url"`
}

Expand Down

0 comments on commit a7424e1

Please sign in to comment.