Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using AppEngine/Go Users API with OAuth: code sample, workflow, any help?

While I am very experienced with the AppEngine/Python runtime, I am a newbie to the Go runtime. My first application is close to being ready to roll out, but I still need to provide a capability for the user to log in. I am hoping to use OpenID, as I would rather not require that the user have a Google Id.

However, it seems that there are no or almost no working examples out there, and the AppEngine documentation explicity omits the contents of the function that I need to implement:

func init() {
    http.HandleFunc("/_ah/login_required", openIdHandler)
}

func openIdHandler(w http.ResponseWriter, r *http.Request) {
    // ...
}

What goes inside the openIdHandler func?

I understand that I need to provide a page that will allow the user to select one of the many OpenId providers and enter their Id for that system. I just don't know what to do after that. What is the workflow? Does anyone know of any sample code that I can look at to get a general idea of what I must do and what data I must handle? All of my well-honed google-fu has lead me nowhere.

To be clear, I am not looking to interact with any of the services provided by these OpenId providers; I do not wish to create Tweets or Buzz. I do not want access to contacts, docs, Wall postings or anything else. I just wanted an authenticated credenital that I can use inside my application to limit a users access to only his or her own data.

like image 732
Adam Crossland Avatar asked Nov 03 '11 02:11

Adam Crossland


1 Answers

If I well understood you — you need openid, not oath. I rewrote python example (Federated login and logout) for go-lang. Hope this help.

package gae_go_openid_demo

import (
    "fmt"
    "os"
    "http"

    "appengine"
    "appengine/user"
)

func init() {
    http.HandleFunc("/", hello)
    http.HandleFunc("/_ah/login_required", openIdHandler)
}

func hello(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    u := user.Current(c)
    if u != nil {
        url, err := user.LogoutURL(c, "/")
        check(err);
        fmt.Fprintf(w, "Hello, %s! (<a href='%s'>Sign out</a>)", u, url)
    } else {
        fmt.Fprintf(w, "Please, <a href='/_ah/login_required'>login</a>.")
    }

}

func openIdHandler(w http.ResponseWriter, r *http.Request) {
    providers := map[string]string {
        "Google"   : "www.google.com/accounts/o8/id", // shorter alternative: "Gmail.com"
        "Yahoo"    : "yahoo.com",
        "MySpace"  : "myspace.com",
        "AOL"      : "aol.com",
        "MyOpenID" : "myopenid.com",
        // add more here
    }

    c := appengine.NewContext(r)
    fmt.Fprintf(w, "Sign in at: ")
    for name, url := range providers {
        login_url, err := user.LoginURLFederated(c, "/", url)
        check(err);
        fmt.Fprintf(w, "[<a href='%s'>%s</a>]", login_url, name)
    }
}

// check aborts the current execution if err is non-nil.
func check(err os.Error) {
    if err != nil {
        panic(err)
    }
}
like image 79
PaulKolbovich Avatar answered Sep 18 '22 12:09

PaulKolbovich