I want to authenticate Android users with a Go AppEngine backend,
I can easily get an ID-token in Android by following http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html
the ID-token payload can be verified with the oauth2/v2 package of the https://code.google.com/p/google-api-go-client/ library.
some installation tweaks are necessary for using it with AppEngine, I found some pointers at http://golangtutorials.blogspot.co.il/2011/11/using-external-api-in-go-appengine.html
according to the doc: "Verify Signature It turns out that this is signed using a Google public/private key pair, and Google publishes the public keys (which we change regularly) at www.googleapis.com/oauth2/v1/certs; go ahead and have a look.
You have to verify that the ID Token, which is actually a JSON Web Token, was signed with one of those certs. Fortunately, there are decent libraries around to do this; in this post, I’ll give pointers for Java, Ruby, and PHP.
The libraries can cache the Google certs and only refresh them when required, so the verification is (almost always) a fast static call."
how do I verify in Go that the token was signed by Google?
this is what I ended up doing (using https://github.com/dgrijalva/jwt-go):
package XXX
import (
"errors"
oauth2 "code.google.com/p/google-api-go-client/oauth2/v2"
"jwt"
"appengine"
"appengine/urlfetch"
)
func getTokeninfo(c appengine.Context, token string) (*oauth2.Tokeninfo, error) {
client := urlfetch.Client(c)
oauth2Svc, err := oauth2.New(client)
if err != nil {
return nil, err
}
return oauth2Svc.Tokeninfo().Id_token(token).Do()
}
func verifyToken(c appengine.Context, token string) (string, error) {
parsedToken, err := jwt.Parse(token)
if err != nil {
c.Debugf(err.Error())
return "", err
}
if parsedToken.Claims["aud"] != "XXX.apps.googleusercontent.com" {
c.Debugf("aud mismatch")
return "", errors.New("Aud mismatch")
}
if (parsedToken.Claims["azp"] != "XXX.apps.googleusercontent.com") &&
(parsedToken.Claims["azp"] != "XXX.apps.googleusercontent.com") {
c.Debugf("azp mismatch")
return "", errors.New("Azp mismatch")
}
ti, err := getTokeninfo(c, token)
if err != nil {
c.Debugf(err.Error())
return "", err
}
if (ti.Issued_to != "XXX.apps.googleusercontent.com") &&
(ti.Issued_to != "XXX.apps.googleusercontent.com") {
c.Debugf("cid mismatch")
return "", errors.New("Client ID mismatch")
}
return ti.User_id, nil
}