Facebook Authentication Provider
* will not re-prompt if the email permission is denied, or if you previously authorized the same FB app without the email scope.
This commit is contained in:
		
							parent
							
								
									3a79827af2
								
							
						
					
					
						commit
						a0763477c5
					
				|  | @ -30,6 +30,7 @@ Valid providers are : | |||
| 
 | ||||
| * [Google](#google-auth-provider) *default* | ||||
| * [Azure](#azure-auth-provider) | ||||
| * [Facebook](#facebook-auth-provider) | ||||
| * [GitHub](#github-auth-provider) | ||||
| * [GitLab](#gitlab-auth-provider) | ||||
| * [LinkedIn](#linkedin-auth-provider) | ||||
|  | @ -87,6 +88,11 @@ Note: The user is checked against the group members list on initial authenticati | |||
| The Azure AD auth provider uses `openid` as it default scope. It uses `https://graph.windows.net` as a default protected resource. It call to `https://graph.windows.net/me` to get the email address of the user that logs in. | ||||
| 
 | ||||
| 
 | ||||
| ### Facebook Auth Provider | ||||
| 
 | ||||
| 1. Create a new FB App from <https://developers.facebook.com/> | ||||
| 2. Under FB Login, set your Valid OAuth redirect URIs to `https://internal.yourcompany.com/oauth2/callback` | ||||
| 
 | ||||
| ### GitHub Auth Provider | ||||
| 
 | ||||
| 1. Create a new project: https://github.com/settings/developers | ||||
|  |  | |||
							
								
								
									
										19
									
								
								api/api.go
								
								
								
								
							
							
						
						
									
										19
									
								
								api/api.go
								
								
								
								
							|  | @ -1,6 +1,7 @@ | |||
| package api | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
|  | @ -31,6 +32,24 @@ func Request(req *http.Request) (*simplejson.Json, error) { | |||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| func RequestJson(req *http.Request, v interface{}) error { | ||||
| 	resp, err := http.DefaultClient.Do(req) | ||||
| 	if err != nil { | ||||
| 		log.Printf("%s %s %s", req.Method, req.URL, err) | ||||
| 		return err | ||||
| 	} | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	resp.Body.Close() | ||||
| 	log.Printf("%d %s %s %s", resp.StatusCode, req.Method, req.URL, body) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return fmt.Errorf("got %d %s", resp.StatusCode, body) | ||||
| 	} | ||||
| 	return json.Unmarshal(body, v) | ||||
| } | ||||
| 
 | ||||
| func RequestUnparsedResponse(url string, header http.Header) (resp *http.Response, err error) { | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -0,0 +1,80 @@ | |||
| package providers | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 
 | ||||
| 	"github.com/bitly/oauth2_proxy/api" | ||||
| ) | ||||
| 
 | ||||
| type FacebookProvider struct { | ||||
| 	*ProviderData | ||||
| } | ||||
| 
 | ||||
| func NewFacebookProvider(p *ProviderData) *FacebookProvider { | ||||
| 	p.ProviderName = "Facebook" | ||||
| 	if p.LoginURL.String() == "" { | ||||
| 		p.LoginURL = &url.URL{Scheme: "https", | ||||
| 			Host: "www.facebook.com", | ||||
| 			Path: "/v2.5/dialog/oauth", | ||||
| 			// ?granted_scopes=true
 | ||||
| 		} | ||||
| 	} | ||||
| 	if p.RedeemURL.String() == "" { | ||||
| 		p.RedeemURL = &url.URL{Scheme: "https", | ||||
| 			Host: "graph.facebook.com", | ||||
| 			Path: "/v2.5/oauth/access_token", | ||||
| 		} | ||||
| 	} | ||||
| 	if p.ProfileURL.String() == "" { | ||||
| 		p.ProfileURL = &url.URL{Scheme: "https", | ||||
| 			Host: "graph.facebook.com", | ||||
| 			Path: "/v2.5/me", | ||||
| 		} | ||||
| 	} | ||||
| 	if p.ValidateURL.String() == "" { | ||||
| 		p.ValidateURL = p.ProfileURL | ||||
| 	} | ||||
| 	if p.Scope == "" { | ||||
| 		p.Scope = "public_profile email" | ||||
| 	} | ||||
| 	return &FacebookProvider{ProviderData: p} | ||||
| } | ||||
| 
 | ||||
| func getFacebookHeader(access_token string) http.Header { | ||||
| 	header := make(http.Header) | ||||
| 	header.Set("Accept", "application/json") | ||||
| 	header.Set("x-li-format", "json") | ||||
| 	header.Set("Authorization", fmt.Sprintf("Bearer %s", access_token)) | ||||
| 	return header | ||||
| } | ||||
| 
 | ||||
| func (p *FacebookProvider) GetEmailAddress(s *SessionState) (string, error) { | ||||
| 	if s.AccessToken == "" { | ||||
| 		return "", errors.New("missing access token") | ||||
| 	} | ||||
| 	req, err := http.NewRequest("GET", p.ProfileURL.String()+"?fields=name,email", nil) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	req.Header = getFacebookHeader(s.AccessToken) | ||||
| 
 | ||||
| 	type result struct { | ||||
| 		Email string | ||||
| 	} | ||||
| 	var r result | ||||
| 	err = api.RequestJson(req, &r) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	if r.Email == "" { | ||||
| 		return "", errors.New("no email") | ||||
| 	} | ||||
| 	return r.Email, nil | ||||
| } | ||||
| 
 | ||||
| func (p *FacebookProvider) ValidateSessionState(s *SessionState) bool { | ||||
| 	return validateToken(p, s.AccessToken, getFacebookHeader(s.AccessToken)) | ||||
| } | ||||
|  | @ -22,6 +22,8 @@ func New(provider string, p *ProviderData) Provider { | |||
| 		return NewMyUsaProvider(p) | ||||
| 	case "linkedin": | ||||
| 		return NewLinkedInProvider(p) | ||||
| 	case "facebook": | ||||
| 		return NewFacebookProvider(p) | ||||
| 	case "github": | ||||
| 		return NewGitHubProvider(p) | ||||
| 	case "azure": | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue