# HG changeset patch # User Mikael Berthe # Date 1494414420 -7200 # Node ID b63095e0f301c23f31b45dddbae5456363bc9631 # Parent 4fb7376fa19a4a0880ccbb23e250c46bad83f143 Add OAuth 2.0 authentication support diff -r 4fb7376fa19a -r b63095e0f301 .travis.yml --- a/.travis.yml Wed May 10 11:06:22 2017 +0200 +++ b/.travis.yml Wed May 10 13:07:00 2017 +0200 @@ -11,6 +11,7 @@ only: - master install: +- go get golang.org/x/oauth2 - go get github.com/pkg/errors - go get github.com/stretchr/testify/assert - go get github.com/sendgrid/rest diff -r 4fb7376fa19a -r b63095e0f301 login.go --- a/login.go Wed May 10 11:06:22 2017 +0200 +++ b/login.go Wed May 10 13:07:00 2017 +0200 @@ -10,10 +10,14 @@ "encoding/json" "strings" + "golang.org/x/oauth2" + "github.com/pkg/errors" "github.com/sendgrid/rest" ) +const oAuthRelPath = "/oauth/" + // UserToken represents a user token as returned by the Mastodon API type UserToken struct { AccessToken string `json:"access_token"` @@ -50,7 +54,7 @@ } req := rest.Request{ - BaseURL: mc.InstanceURL + "/oauth/token", + BaseURL: mc.InstanceURL + oAuthRelPath + "token", Headers: hdrs, QueryParams: opts, Method: rest.Post, @@ -86,3 +90,39 @@ } return nil } + +// LoginOAuth2 handles OAuth2 authentication +// If code is empty, the URL to the server consent page will be returned; +// if not, the user token is set. +func (mc *Client) LoginOAuth2(code string, scopes []string) (string, error) { + if mc == nil { + return "", ErrUninitializedClient + } + + conf := &oauth2.Config{ + ClientID: mc.ID, + ClientSecret: mc.Secret, + Scopes: scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: mc.InstanceURL + oAuthRelPath + "authorize", + TokenURL: mc.InstanceURL + oAuthRelPath + "token", + }, + RedirectURL: NoRedirect, + } + + if code == "" { + // URL to consent page to ask for permission + // for the scopes specified above. + return conf.AuthCodeURL("state", oauth2.AccessTypeOffline), nil + } + + // Return token + t, err := conf.Exchange(nil, code) + if err != nil { + return "", errors.Wrap(err, "cannot convert code into a token") + } + if t == nil || t.AccessToken == "" { + return "", errors.New("empty token") + } + return "", mc.SetUserToken(t.AccessToken, "", "", scopes) +}