Comments (14)
Hi @vikforfda, @BlasiusSecundus, I did indeed manage to get a working solution. I can't remember the exact resource I used for it, but the links you shared are very close. I'm not very happy with the solution in the sense that I would've hoped the library would've supported this case specifically as it's something supported by Apollo out of the box with the connection params. I know there's no "best practice" or even recommended practice for handling auth tokens with subscriptions, but it needs to start from somewhere! Hope this code is helpful!
@Component
internal class GraphQLSubscriptionAuthenticationListener(
private val authenticationProvider: AuthenticationProvider,
) : ApolloSubscriptionConnectionListener {
override fun onConnect(session: SubscriptionSession, message: OperationMessage) {
val authToken = (message.payload as Map<*, *>)[AUTH_TOKEN_PAYLOAD_KEY] as? String
if (authToken != null) {
val authentication = authenticationProvider.authenticate(BearerTokenAuthenticationToken(authToken))
SecurityContextHolder.getContext().authentication = authentication
session.userProperties[AUTHENTICATION_USER_PROPERTY_KEY] = authentication
}
}
override fun onStart(session: SubscriptionSession, message: OperationMessage) {
val authentication = session.userProperties[AUTHENTICATION_USER_PROPERTY_KEY] as? Authentication
SecurityContextHolder.getContext().authentication = authentication
}
companion object {
private const val AUTH_TOKEN_PAYLOAD_KEY = "authToken"
private const val AUTHENTICATION_USER_PROPERTY_KEY = "AUTHENTICATION"
}
}
Frontend client creation:
const underlyingSubscriptionClient = new SubscriptionClient(getUrl(Path.GraphqlSubscriptions), {
// https://www.npmjs.com/package/subscriptions-transport-ws
connectionParams: async () => ({
authToken: jwtToken,
}),
lazy: true,
})
Where possible, it would still be great to get some more customisability in the WebSocketClientConfigurator where can have the ability for a more flexibility implementation.
from graphql-spring-boot.
@BlasiusSecundus might you have a recommendation here?
from graphql-spring-boot.
Hi @maxkramer were you able to figure out how to send oAuth access tokens to Spring Boot based GraphQL dynamically / programmatically? We are trying to do the same thing where we are launching GraphQL from a web page. We want the web page to pass the oAuth JWT access tokens so that GraphQL can enforce authorization when user executes queries using the information in the token.
from graphql-spring-boot.
Hi @maxkramer, sorry for not responding earlier. AFAIK there is no standard way to handle authentication via GraphQL subscriptions.
One possibility is to put the auth token in the connection_init
(via providing a payload for the GraphQLTestSubscription.init
method) or the start
message payload. Then handling it on the other side by providing an implementation of ApolloSubscriptionConnectionListener
.
Then verifying the token and putting necessary things into Spring Security context. See also graphql-java-kickstart/graphql-java-servlet#134
from graphql-spring-boot.
See also a similar approach of the Apollo Server JS implementation: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#onconnect-and-ondisconnect
from graphql-spring-boot.
@maxkramer @BlasiusSecundus Thanks for sharing your solutions. I have one clarifying question for @maxkramer (I am new to Playground). I see in your code you are referring to ApolloSubscriptionConnectionListener. In your case did you use the Apollo Server version of GraphQL since we want to use the Open source version of GraphQL
from graphql-spring-boot.
@maxkramer @BlasiusSecundus Will this work with the embedded /playground
? please see my question here.
from graphql-spring-boot.
@skesani we're just discussing the webhooks here, but re the headers, I haven't personally played around with setting them automatically via yaml as our access tokens aren't long living. Somebody I worked with in the past created a bookmark that ran some js that fetched a new token and injected it automatically into the http headers section. But according to the docs, I believe it should be this in the application.yaml:
graphql:
playground:
headers:
Authorization: Bearer ey.someToken
There's also a graphql.playground.settings.editor.reuse-headers
that perhaps is related?
@vikforfda we're using the graphql kickstart spring boot starter, I'm not sure which one that's using as we haven't had a need to look into anything further.
from graphql-spring-boot.
In your case did you use the Apollo Server version of GraphQL since we want to use the Open source version of GraphQL
@vikforfda ApolloSubscriptionConnectionListener
is actually part of this library: https://github.com/graphql-java-kickstart/graphql-java-servlet/blob/master/graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionConnectionListener.java
from graphql-spring-boot.
@skesani Yes, it will work. The variables set in the "HTTP headers" tab will be sent to the server as the payload
of the connection_init
message.
from graphql-spring-boot.
@skesani Yes, it will work. The variables set in the "HTTP headers" tab will be sent to the server as the
payload
of theconnection_init
message.
@BlasiusSecundus could you provide any sample to set the token programmatically?
I am thinking to do like this.
`
import graphql.kickstart.playground.GraphQLPlaygroundConfigurer;
import org.springframework.stereotype.Component;
@component
public class CustomGraphQLPlaygroundConfigurer implements GraphQLPlaygroundConfigurer {
@Override
public void configure(GraphQLPlaygroundConfigBuilder builder) {
// Add JavaScript file to the GraphQL Playground page
builder.addPlugin(getCustomPlugin());
}
private String getCustomPlugin() {
// Get token from some source (e.g. database, config file, etc.)
String token = "my-token";
// Create JavaScript code that sets the token value in the GraphQL request headers
return "window.addEventListener('load', function (event) {\n" +
" GraphQLPlayground.init(document.getElementById('root'), {\n" +
" settings: {\n" +
" 'request.credentials': 'same-origin',\n" +
" 'X-AUTH-TOKEN': '" + token + "'\n" +
" }\n" +
" });\n" +
"});";
}
}
`
from graphql-spring-boot.
@skesani Variables from configuration are already passed to Playground in PlaygroundController. That would be the natural place to extend its functionality so that it can take headers from sources other than configuration properties. (E.g. some configurator bean as you proposed).
from graphql-spring-boot.
Returning to the original question / bug report, I think this issue should be closed:
- I don't see any bug or necessary improvement as far as
GraphQLTestSubscription
is concerned. It is possible to send the authorization token to the server as part of the payload of theconnection_init
message, which is sort of the preferred way. Playground automatically does this (sending the "HTTP Headers" as payload ofconnection_init
) out of the box. - There are two related, but functionally independent improvement suggested in this discussion:
- built-in support for authenticated subscriptions (currently, the necessary credentials processing, Spring Security integration etc. has to be done by the user of the library)
- more flexibility when configuring default headers for developer utilities (Playground and others) - currently, it is only possible using configuration properties, which may not be suitable for some more advanced scenarios (e.g. obtaining access token from an authentication server when opening Playground)
These two should be handled as separate issues (flagged as enhancement).
from graphql-spring-boot.
@skesani Variables from configuration are already passed to Playground in PlaygroundController. That would be the natural place to extend its functionality so that it can take headers from sources other than configuration properties. (E.g. some configurator bean as you proposed).
@BlasiusSecundus I created this repo and added MyConfig and MyPlaygroundController extends PlaygroundController however, I am unable to override the headers, could you please take a look?
https://github.com/skesani/graphql-playground
from graphql-spring-boot.
Related Issues (20)
- Customize SimpleDataFetcherExceptionHandler to avoid logException for certain errors HOT 1
- Spring Boot Graphql Remove duplicates from the Response
- SpringDoc bean name conflict error HOT 1
- Latest 15.0.0 version is not compatible with Spring boot 3.0.2 and spring security 6.0.1 HOT 3
- How to set the bearer token dynamically in graphql-spring-boot playground
- different data response for nullable and non-nullable responses
- @connection not working after Spring Boot and graphql upgrade HOT 1
- CVE-2023-28867 affects all recent versions (including v15)
- `ErrorHandlerSupplier` not always initialized when we first need it
- Query returning the result of previously timed out query
- Support check origin for websocket to secure against cross-site attacks
- Support CSRF on websockets to secure against cross-site attacks
- When upgrading to Spring Boot 3.1.0 we get in the response the tracing information under extensions HOT 2
- MetricsInstrumentation does not implement updated API of TracingInstrumentation provided by graphql-java
- Maven seems to confuse graphql-java version HOT 4
- Request scoped beans aren't accessible in mutation and query resolvers
- Virtual threads support
- Cannot disable tracing response with graphql-spring-boot-starter version 15 HOT 4
- No qualifying bean of type 'com.graphql.spring.boot.test.GraphQLTestTemplate' available : graphql-spring-boot-starter-test:jar:15.0.0
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from graphql-spring-boot.