Golang : Login(Authenticate) with Facebook example
By today's Internet standard, if you want to create a website or app that allows user to login, it won't be complete without a Facebook login button.
In this tutorial, we will explore how to :
- generate a Facebook Login URL string and bind a "Login with Facebook" button to the URL.
- generate access token from the returned
code
after login successfully. - dump out all the data returned by Facebook (depending on the scope - email, userbirthday, userlocation, useraboutme).
- get some data such as id, birthday, username and profile photo.
Please take note that, this tutorial uses couple of third party packages :
"github.com/golang/oauth2"
"github.com/antonholmquist/jason"
NOTE : Because I've executed this code in one of my Digital Ocean's droplet with an IP-address instead of domain name. I need to "fool" the Facebook Developers App Setting by setting the Mobile Site URL
to http://<ip address>:8080/
at https://developers.facebook.com/apps/<app id>/settings/
. You don't have to do this if you are executing the code in the domain name specified in the Facebook App Site URL
setting.
NOTE : This tutorial assumes that you've setup your Facebook App and already have the AppID and Secret.
Here you go :
package main
import (
"fmt"
"github.com/antonholmquist/jason"
"github.com/golang/oauth2"
"net/http"
"strconv"
"strings"
)
type AccessToken struct {
Token string
Expiry int64
}
func readHttpBody(response *http.Response) string {
fmt.Println("Reading body")
bodyBuffer := make([]byte, 5000)
var str string
count, err := response.Body.Read(bodyBuffer)
for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
if err != nil {
}
str += string(bodyBuffer[:count])
}
return str
}
//Converts a code to an Auth_Token
func GetAccessToken(client_id string, code string, secret string, callbackUri string) AccessToken {
fmt.Println("GetAccessToken")
//https://graph.facebook.com/oauth/access_token?client_id=YOUR_APP_ID&redirect_uri=YOUR_REDIRECT_URI&client_secret=YOUR_APP_SECRET&code=CODE_GENERATED_BY_FACEBOOK
response, err := http.Get("https://graph.facebook.com/oauth/access_token?client_id=" +
client_id + "&redirect_uri=" + callbackUri +
"&client_secret=" + secret + "&code=" + code)
if err == nil {
auth := readHttpBody(response)
var token AccessToken
tokenArr := strings.Split(auth, "&")
token.Token = strings.Split(tokenArr[0], "=")[1]
expireInt, err := strconv.Atoi(strings.Split(tokenArr[1], "=")[1])
if err == nil {
token.Expiry = int64(expireInt)
}
return token
}
var token AccessToken
return token
}
func Home(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// generate loginURL
fbConfig := &oauth2.Config{
// ClientId: FBAppID(string), ClientSecret : FBSecret(string)
// Example - ClientId: "1234567890", ClientSecret: "red2drdff6e2321e51aedcc94e19c76ee"
ClientID: "", // change this to yours
ClientSecret: "",
RedirectURL: "http://<domain name and don't forget port number if you use one>/FBLogin", // change this to your webserver adddress
Scopes: []string{"email", "user_birthday", "user_location", "user_about_me"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://www.facebook.com/dialog/oauth",
TokenURL: "https://graph.facebook.com/oauth/access_token",
},
}
url := fbConfig.AuthCodeURL("")
// Home page will display a button for login to Facebook
w.Write([]byte("<html><title>Golang Login Facebook Example</title> <body> <a href='" + url + "'><button>Login with Facebook!</button> </a> </body></html>"))
}
func FBLogin(w http.ResponseWriter, r *http.Request) {
// grab the code fragment
w.Header().Set("Content-Type", "text/html; charset=utf-8")
code := r.FormValue("code")
ClientId := "" // change this to yours
ClientSecret := ""
RedirectURL := "http://<domain name and don't forget port number if you use one>/FBLogin"
accessToken := GetAccessToken(ClientId, code, ClientSecret, RedirectURL)
response, err := http.Get("https://graph.facebook.com/me?access_token=" + accessToken.Token)
// handle err. You need to change this into something more robust
// such as redirect back to home page with error message
if err != nil {
w.Write([]byte(err.Error()))
}
str := readHttpBody(response)
// dump out all the data
// w.Write([]byte(str))
// see https://www.socketloop.com/tutorials/golang-process-json-data-with-jason-package
user, _ := jason.NewObjectFromBytes([]byte(str))
id, _ := user.GetString("id")
email, _ := user.GetString("email")
bday, _ := user.GetString("birthday")
fbusername, _ := user.GetString("username")
w.Write([]byte(fmt.Sprintf("Username %s ID is %s and birthday is %s and email is %s<br>", fbusername, id, bday, email)))
img := "https://graph.facebook.com/" + id + "/picture?width=180&height=180"
w.Write([]byte("Photo is located at " + img + "<br>"))
// see https://www.socketloop.com/tutorials/golang-download-file-example on how to save FB file to disk
w.Write([]byte("<img src='" + img + "'>"))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", Home)
mux.HandleFunc("/FBLogin", FBLogin)
http.ListenAndServe(":8080", mux)
}
Output :
References :
By Adam Ng
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+4.6k Which content-type(MIME type) to use for JSON data
+26.5k Golang : Find files by extension
+5k Javascript : Change page title to get viewer attention
+6.7k Golang : Calculate BMI and risk category
+9.5k Golang : List available AWS regions
+8.3k Python : Fix SyntaxError: Non-ASCII character in file, but no encoding declared
+9.8k Golang : Test a slice of integers for odd and even numbers
+13.6k Golang : Compress and decompress file with compress/flate example
+7.5k Golang : Ways to recover memory during run time.
+13.3k Golang : Activate web camera and broadcast out base64 encoded images
+38.7k Golang : How to iterate over a []string(array)
+33.6k Golang : Proper way to set function argument default value