Not an app engine context

578 views
Skip to first unread message

mzh...@snapchat.com

unread,
May 14, 2018, 8:23:36 PM5/14/18
to google-appengine-go
Hi I was trying the appengine user package here: https://cloud.google.com/appengine/docs/standard/go/users/
The related code segment is this:

func (h GraphiQL) Auth(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Content-type", "text/html; charset=utf-8")

ctx := appengine.NewContext(r)
u := user.Current(ctx)
if u == nil {
url, err := user.LoginURL(ctx, "/")
fmt.Fprintf(w, `<a href="%s">Sign in or register</a>`, url)
return err
}
url, err := user.LogoutURL(ctx, "/")
fmt.Fprintf(w, `Welcome, %s! (<a href="%s">sign out</a>)`, u, url)
return err
}

But I got the error message "not an App Engine context" by the LoginURL call. Is there any specific field I need to check against my http request? The error message doesn't provide much useful messages.

Kyle Finley

unread,
May 15, 2018, 10:27:32 AM5/15/18
to google-appengine-go
Hi, 

The issue may be due to how you're registering the "Auth" handler. I believe the App Engine Context is created by reading some information from request headers. Maybe it's being stripped?
If you could share how your are registering the handler, someone might be able to provide more help. 

One thing to note: if you are just attempting to secure the GraphiQL endpoint, a simple solution would be to just serve a static file, and restrict access via your app.yaml file (https://cloud.google.com/appengine/docs/standard/go/config/appref#handlers_login), e.g.


- url: /graphiql
script: _go_app
# secure: always
login: admin

 
I hope that helps. If you have any other questions about setting up GraphQL on Go AE please let me know. I have a setup running in production, I can share some code.

Kyle

mzh...@snapchat.com

unread,
May 15, 2018, 1:34:41 PM5/15/18
to google-appengine-go
Hi Kyle, thanks for the reply. My task is to setup an email whitelist to my graphiql endpoint, not sure the app.yaml solution is flexible enough for doing that?

Here is the related code for the server:

var (
addr              = ":8080"
readHeaderTimeout = 1 * time.Second
writeTimeout      = 10 * time.Second
idleTimeout       = 90 * time.Second
maxHeaderBytes    = http.DefaultMaxHeaderBytes
)

func main() {
       .....
       mux := http.NewServeMux()
       mux.Handle("/", handler.GraphiQL{})
       ....
       s := &http.Server{
Addr:              addr,
ReadHeaderTimeout: readHeaderTimeout,
WriteTimeout:      writeTimeout,
IdleTimeout:       idleTimeout,
MaxHeaderBytes:    maxHeaderBytes,
Handler:           mux,
}

        if err := s.ListenAndServe(); err != nil {
glog.Infof("server.ListenAndServe failed: %s", err.Error())
}
}


and in the package handler:

type GraphiQL struct{}

func (h GraphiQL) ServeHTTP(w http.ResponseWriter, r *http.Request) {
       err := h.Auth(w, r)
if err != nil {
fmt.Println(err.Error())
return
}
        .....
}

func (h GraphiQL) Auth(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Content-type", "text/html; charset=utf-8")
fmt.Println(r.Header)
ctx := appengine.NewContext(r)
u := user.Current(ctx)
if u == nil {
url, err := user.LoginURL(ctx, "/")
fmt.Fprintf(w, `<a href="%s">Sign in or register</a>`, url)
return err
}
url, _ := user.LogoutURL(ctx, "/")
fmt.Fprintf(w, `Welcome, %s! (<a href="%s">sign out</a>)`, u, url)
return nil
}


The request is sent from my browser, and I print out the header, doesn't seem to be truncated though. Do you know is there any specific field in header I should double check?

Kyle Finley

unread,
May 15, 2018, 9:07:22 PM5/15/18
to google-appengine-go
> My task is to setup an email whitelist to my graphiql endpoint, not sure the app.yaml solution is flexible enough for doing that?

You could restrict to Project admins, but you're correct, for an email whitelist you would need a custom solution. 

App Engine Standard has some characteristics that make the setup a little bit different from a traditional Go app or even AE Flexible environment.
Some documentation (https://cloud.google.com/appengine/docs/standard/go/building-app/creating-your-application) an Example main.go (https://github.com/GoogleCloudPlatform/golang-samples/blob/master/appengine/gophers/gophers-1/main.go)

With AE Standard your setup would look more like this, note there's no need for the ListenAndServe function:

package main

import (
  "fmt"
  "net/http"

)

func main() {
  g := handler.GraphiQL{}
  http.HandleFunc("/", g.ServeHTTP)
  appengine.Main() // Starts the server to receive requests
}

Alternatively, if you are deploying to the Flexible environment, I don't believe the appengine/user package is available (https://cloud.google.com/appengine/docs/flexible/go/authenticating-users). You'll have to use one of the alternative authentication methods, which will probably require some JavaScript, i.e. load the page and either authenticate client side or submit a JWT and parse it on the server. I don't think Firebase Auth or Google Sign in offer a cookie solution, but I could be wrong.

mzh...@snapchat.com

unread,
May 16, 2018, 1:04:34 AM5/16/18
to google-appengine-go
Oh thanks a lot for the explain! Yeah, I'm deploying to flex env, just realize the appengine go package is not used for that....
Reply all
Reply to author
Forward
0 new messages