I’ve been struggling to get the Mirror-Quickstart-Go up and running. A few months back I was able to get it running on an appengine instance without any trouble at all. Recently though, I decided to blow away the test code I had on my appengine and start over. Unfortunately setting up the quickstart was not as easy this time. After following the usual steps of setting up a project, creating the client IDs and configuring the project with the proper information, I deployed it and became stuck in an authorization redirect loop. The only error I received in the Log viewer was:
Get Token: datastore: no such entity
After double and triple and quadruple checking that I had all the right IDs everywhere, I figured out a way to be able to debug the project and start tracking down the issue. There are only a handful of URLs that the quickstart is configured to handle. Anything else and it will just return a 404 error, as it should. I decided to use this to my advantage by modifying the main.go file to change all of the sections that performed HTTP redirects to redirect to pages such as “/useridempty”.
**if** userId **==**"" {
//http.Redirect(w, r, "/auth", http.StatusFound)
http.Redirect(w, r, "/useridempty", http.StatusFound)
**return** **nil**
}
This allowed me to track it down to line 84: t := authTransport(c, userId) authTransport was returning nil. Continuing this into the util.go file, the line that was causing trouble was line 94, specifically the datastore.Get(c, key, tok) portion. Turns out, that the token needed to authenticate wasn’t being stored in the database, to the error (and subsequently the redirect) being caused by this was accurate.
I went back to the oauth2callback method, since I knew that was getting called at least, and visually stepped through the code cross referencing what was happening with what the code should be doing. This lead me to the storeCredential method. The storeCredential method (used on line 78 in the auth.go and declared on line 83 in util.go. The storeCredential method returns an error, but that error was not being checked. I modified the usage of storeCredential in the auth.go file to return the error like so:
if err = storeCredential(c, userId, tok); err != nil {
return fmt.Errorf("Unable to store credential: %s", err)
}
This resulted in the following error: Unable to store credential: datastore: unsupported struct field type: map[string]string
After some digging around, I found that storing map objects in the datastore is no longer supported. I’m not sure exactly when it became unsupported, but the fact of the matter remains that it just plain won’t work any more. The Token object from the oauth2 library contained an “Extras” field of type map[string]string and since it was a Token object that was being stored in the datastore, that’s why it’s failing. The token never got saved, so of course it wasn’t there when it tried to read it out, but with the way the demo was calling the storeCredential method, the error was being dropped and passing by silently.
In order to fix the error, I created a simple “SimpleToken” struct that contained the same signature as the Token object, just without the “Extras” field. I also set up a couple of short methods to turn a oauth.Token into a SimpleToken and vice versa. In the util.go file, I changed the storeCredential method to take in a *SimpleToken instead of a *oauth.Token and the authTransport method to convert the oauth.Token object into a SimpleToken object before passing it to the datastore.Get method. In the auth.go file, the only thing that had to change was in the oauth2callbackHandler method. The method was updated to convert the oauth.Token object into a SimpleToken object before the call to storeCredential.
Once these changes were completed and the project redeployed to AppEngine, everything loaded up properly and began working. It was a very annoying issue and troublesome to track down, but once the root problem was found, the fix was surprisingly simple. Once I get around to cleaning up the code a bit I’ll fork the project and make a pull request so that anyone else pulling down the Go quickstart won’t have these same issues. I’d hope that the oauth or datastore library would be updated to properly work around the change to the datastore that now prevents storing map types.
Originally published October 26, 2013 at blog.sohjsolwin.com.
Top comments (0)