Search code examples
google-app-enginegooauth-2.0facebook-oauthmartini

Martini oauth2callback redirects to oauth2error after adapting to GAE


Code below works perfectly on local server, but when adapted to Google app engine(func main is changed to init and package name is set from main to test app) oauth2callback request is not working anymore, below request is redirected to oauth2error handler.

http://testapp.com/oauth2callback?code=OAUTHRESPONSEFROMFACEBOOK&state=%2F

package testapp

import (
    "github.com/go-martini/martini"
    goauth2 "github.com/golang/oauth2"
    "github.com/martini-contrib/oauth2"
    "github.com/martini-contrib/sessions"
    "net/http"
)

func init() {
    m := martini.Classic()
    m.Use(sessions.Sessions("my_session", sessions.NewCookieStore([]byte("secret123"))))
    m.Use(oauth2.Facebook(
        goauth2.Client("AppID", "AppSecret"),
        goauth2.RedirectURL("http://testapp.com/oauth2callback"),
        goauth2.Scope("email,user_birthday,user_friends,publish_actions,user_location,user_photos"),
    ))
    // Tokens are injected to the handlers
    m.Get("/", func(tokens oauth2.Tokens) string {
        if tokens.Expired() {
            return "not logged in, or the access token is expired"
        }
        return "logged in"
    })

    // Routes that require a logged in user
    // can be protected with oauth2.LoginRequired handler.
    // If the user is not authenticated, they will be
    // redirected to the login path.
    m.Get("/restrict", oauth2.LoginRequired, func(tokens oauth2.Tokens) string {
        return tokens.Access()
    })

    http.Handle("/", m)
}

Solution

  • My guess is that you need to inject App Engine context into the Get method.

    According to this issue on Go Martini repo, you can do as follow:

    func AppEngine(m martini.Context, r *http.Request) {
        m.MapTo(appengine.NewContext(r), (*appengine.Context)(nil))
    }
    
    func init() {
        m := martini.Classic()
        m.Use(AppEngine)
    
        // ...
    
        m.Get("/", func(tokens oauth2.Tokens, c appengine.Context) string {
            if tokens.Expired() {
                return "not logged in, or the access token is expired"
            }
            return "logged in"
        })
    
        m.Get("/restrict", oauth2.LoginRequired, func(tokens oauth2.Tokens, c appengine.Context) string {
            return tokens.Access()
        })
    }