graphql

urzds 2019-03-22T15:52:40.048Z

Hi! Can someone please point me to instructions on how to add authentication to an existing Lacinia GraphQL interface?

urzds 2019-03-22T16:04:10.052Z

Generally it appears that for GraphQL-over-HTTP, on the client, I add a header to the request, that I then need to extract it on the server and place it in the context? How do I do that with Lacinia Pedestal? I only found a blog post explaining it for Ring. And then there is GraphQL-over-WS, where I don't know at all how to do this. The only angle I see so far is via the WebSocket's initial payload, but the connection might be created too early...

2019-03-22T16:38:04.053600Z

I haven't looked around at what other people are doing but at work I am using lacinia for graphql over http://socket.io (websockets + long polling fallback), and the way we do authentication there is when a client initial connections, before they can do any graphql operations, they have to send a token that authenticates them

2019-03-22T16:38:34.054100Z

so it behaves very much like talking to a server over a stateful connection (which it is)

2019-03-22T17:21:27.055Z

@urzds i've done it in two ways over websocket, either with the initial payload (better) or by cookies on the websocket connection request (not so nice)

2019-03-22T17:21:35.055200Z

and by header on http

2019-03-22T17:22:28.055700Z

in each case, you probably want to use interceptors to get the token into the lacinia app context

urzds 2019-03-22T17:25:06.055900Z

Thanks!

urzds 2019-03-22T17:25:39.056700Z

So I'll try delaying the WebSocket connection until I have authenticated via HTTP.

2019-03-22T17:29:10.057300Z

the header is not super challenging, you can write a pedestal interceptor that drops requests when non-authenticated

2019-03-22T17:29:30.057600Z

Let me see if I can find a snippet for ya

2019-03-22T17:33:33.060Z

(assume lacinia pedestal is aliased as lp), You can pass an option map to lp/service-map with key :interceptors. You can use the default interceptors, lp/default-interceptors, and use lp/inject to inject your own into that interceptor chain. Then its just a matter of writing an intercepter that terminates when the auth header is malformed/invalid/…

urzds 2019-03-22T19:57:06.060700Z

@lennart.buit (default-interceptors compiled-schema options) is a function, which needs the service map...? How is that supposed to work?

2019-03-22T20:00:27.061400Z

No, — it needs an option map ^^

urzds 2019-03-22T20:05:01.065300Z

So I go from

(-> compile-graphql-schema
  (lp/service-map {:my :options})
  http/create-server
  ...)
to:
(let [compiled-schema (compile-graphql-schema)
      options {:my :options}
      default-interceptors (lp/default-interceptors compiled-schema options)
      interceptors (lp/inject default-interceptors authorisation-interceptor :after ::lp/inject-app-context)]
  (-> compiled-schema
    (lp/service-map
      (assoc options
        :interceptors interceptors))
    http/create-server
    ...)
?

urzds 2019-03-22T20:06:00.065700Z

@lennart.buit ^

2019-03-22T20:07:43.066600Z

Looks about right, but I can’t check for you right now ^^

urzds 2019-03-22T20:11:13.067Z

OK, I'll try that.

urzds 2019-03-22T20:36:25.067500Z

I can't get it to work. My authorisation-interceptor is never called.

urzds 2019-03-22T20:39:39.068Z

But I can see it in the service map for the GET /graphql and POST /graphql routes.

urzds 2019-03-22T22:05:07.068800Z

re-graph appears to be using the WebSocket for everything, if it has one. So nothing went through the GraphQL HTTP endpoint, and no HTTP interceptors were being applied.

2019-03-22T22:16:55.069900Z

hah! that explains. I know that in Apollo, you need to define a link that splits queries/mutations from subscriptions such that not all your traffic goes over the ws link, maybe the same applies for re-graph