Hi! Can someone please point me to instructions on how to add authentication to an existing Lacinia GraphQL interface?
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...
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
so it behaves very much like talking to a server over a stateful connection (which it is)
@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)
and by header on http
in each case, you probably want to use interceptors to get the token into the lacinia app context
Thanks!
So I'll try delaying the WebSocket connection until I have authenticated via HTTP.
the header is not super challenging, you can write a pedestal interceptor that drops requests when non-authenticated
Let me see if I can find a snippet for ya
(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/…
@lennart.buit (default-interceptors compiled-schema options)
is a function, which needs the service map...? How is that supposed to work?
No, — it needs an option map ^^
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
...)
?Looks about right, but I can’t check for you right now ^^
OK, I'll try that.
I can't get it to work. My authorisation-interceptor
is never called.
But I can see it in the service map for the GET /graphql
and POST /graphql
routes.
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.
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