Clean way to write authentication for Go.
This package was inspired by https://github.com/intridea/omniauth (written in Ruby) and http://github.com/markbates/goth (written in Go).
- Support both OAuth 1.0a and OAuth2
- Have a long list of providers and is easy to write new ones.
$ go get github.com/tamnd/gauth
Here are the list of supported providers. Would you love to see more providers? Feel free to contribute ones by create your own repository or create pull requests!
I use the list as reference. When porting providers directly from those gems, I also keep the author of the gems as author of the providers.
Please keep the list in alphabetical order
Provider | Description | Author | Is Official? |
---|---|---|---|
AngelList | Authenticate to AngelList using OAuth2. | railsjedi | No |
Aol | Authenticate to Aol using OAuth2. | pianosnake | No |
App.net | Authenticate to App.net using OAuth2. | phuu | No |
Behance | Authenticate to Behance using OAuth2. | sandboxws | No |
Box | Authenticate to Box using OAuth2. | iCoreTech, Inc. | No |
Dropbox | Authenticate to Dropbox using OAuth2. | bamorim | No |
Authenticate to Facebook using OAuth2. | tamnd | No | |
Foursquare | Authenticate to Foursquare using OAuth2. | arunagw | No |
Authenticate to Instagram using OAuth2. | tamnd | No | |
Meetup | Authenticate to Meetup using OAuth2. | tapster | No |
First, import GAuth and create OAuth provider
import (
"github.com/tamnd/gauth"
"github.com/tamnd/gauth/provider/facebook"
)
// Create facebook provider
var provider = facebook.New("FACEBOOK_KEY", "FACEBOOK_CLIENT_SECRET", "http://localhost:8080/auth/facebook/callback")
Next, define a handler for GET /auth/facebook
. This will redirect the user to the facebook login page.
func login(w http.ResponseWriter, r *http.Request) {
authURL, _, err := provider.AuthURL("state")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, authURL, http.StatusTemporaryRedirect)
}
Then define the handler for callback request at /auth/facebook/callback
:
func callback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
// Get access token from verification code.
token, err := provider.Authorize(code)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Get the authenticating user
user, err := provider.User(token)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Marshal user info and write to the response.
output, _ := json.Marshal(user)
w.Write([]byte(output))
}
Finally, we register those handlers and start the server:
func main() {
fmt.Println("Start listening on :8080")
http.Handle("/auth/facebook", http.HandlerFunc(login))
http.Handle("/auth/facebook/callback", http.HandlerFunc(callback))
http.ListenAndServe(":8080", nil)
}
See the full source code at examples/facebook.go.
Writing new provider is pretty easy. You just need to define OAuth endpoints:
package yoursite
import "github.com/tamnd/gauth/oauth2"
var Endpoint = oauth2.Endpoint{
AuthURL: "https://yoursite.com/oauth2/auth",
TokenURL: "https://yoursite.com/oauth2/token",
}
and define a function User
to get user info from an access token:
package yoursite
import "github.com/tamnd/gauth"
func User(token *gauth.AccessToken) (*gauth.User, error) {
// Get the user info here...
}
For example, here is the Facebook Authentication Provider:
package facebook
import (
"github.com/tamnd/gauth"
"github.com/tamnd/gauth/oauth2"
)
var Endpoint = oauth2.Endpoint{
AuthURL: "https://www.facebook.com/dialog/oauth",
TokenURL: "https://graph.facebook.com/oauth/access_token",
}
func New(clientId string, secret string, callbackURL string, scopes ...string) gauth.Provider {
provider := &oauth2.Provider{
Endpoint: Endpoint,
UserFn: User,
}
provider.Init(clientId, secret, callbackURL)
return provider
}
package facebook
import (
"net/url"
"github.com/tamnd/gauth"
"github.com/tamnd/httpclient"
)
var endpointProfile = "https://graph.facebook.com/me?fields=email,first_name,last_name,link,bio,id,name,picture,location"
func User(token *gauth.AccessToken) (*gauth.User, error) {
URL := endpointProfile + "&access_token=" + url.QueryEscape(token.Token)
u := struct {
ID string `json:"id"`
Email string `json:"email"`
Bio string `json:"bio"`
Name string `json:"name"`
Link string `json:"link"`
Picture struct {
Data struct {
URL string `json:"url"`
} `json:"data"`
} `json:"picture"`
Location struct {
Name string `json:"name"`
} `json:"location"`
}{}
err := httpclient.JSON(URL, &u)
if err != nil {
return nil, err
}
user := gauth.User{
ID: u.ID,
Name: u.Name,
Email: u.Email,
Username: u.Name,
Location: u.Location.Name,
Description: u.Bio,
Avatar: u.Picture.Data.URL,
Raw: u,
}
return &user, nil
}
- Fork repository
- Create a feature branch
- Open a new pull request
- Create an issue for bug report or feature request
- Nguyen Duc Tam
- [email protected]
- http://twitter.com/tamnd87
The MIT License (MIT). Please see LICENSE for more information.
Copyright (c) 2015 Nguyen Duc Tam, [email protected]