Skip to content
Permalink
Browse files

Merge pull request #111 from netlify/facebook_provider

Implement Facebook provider.
  • Loading branch information...
biilmann committed Oct 4, 2017
2 parents a04e0cd + a7424e1 commit 7b9f9290191a5e911d096ce3938822225a2a2d49
Showing with 79 additions and 0 deletions.
  1. +2 −0 api/external.go
  2. +75 −0 api/provider/facebook.go
  3. +1 −0 api/provider/provider.go
  4. +1 −0 conf/configuration.go
@@ -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)
}
@@ -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
}
@@ -10,6 +10,7 @@ import (
const (
avatarURLKey = "avatar_url"
nameKey = "full_name"
aliasKey = "slug"
)

type UserProvidedData struct {
@@ -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"`
}

0 comments on commit 7b9f929

Please sign in to comment.
You can’t perform that action at this time.