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 :

login with facebook tutorial home page

result after login

References :

https://developers.facebook.com/

http://godoc.org/golang.org/x/oauth2





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