How to handle authorization in subscriptions? #1825
Replies: 7 comments 4 replies
-
|
Beta Was this translation helpful? Give feedback.
-
I got it till the part of the I do not know how to access the |
Beta Was this translation helpful? Give feedback.
-
Here is a simple example: // appContext.go
const (
AppContextKey = "appContext"
)
type AppContext struct {
Token string
UserId string
Cancel context.CancelFunc
}
func ForAppContext(ctx context.Context) *AppContext {
c, _ := ctx.Value(AppContextKey).(*AppContext)
return c
} // init.go
h := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &resolver.Resolver{}}))
// ...
h.AddTransport(transport.Websocket{
Upgrader: websocket.Upgrader{
HandshakeTimeout: time.Minute,
CheckOrigin: func(r *http.Request) bool {
// we are already checking for CORS
return true
},
EnableCompression: true,
},
InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
if token := initPayload.Authorization(); middleware.CouldBetoken(token) {
if intro, err := oauth2.IntrospectToken(token[7:], false); err == nil && intro != nil && oauth2.IsIntrospectionValid(intro) {
nctx, cancel := context.WithCancel(ctx)
return context.WithValue(nctx, middleware.AppContextKey, &middleware.AppContext{
Token: token[7:],
UserId: intro.Sub,
Cancel: cancel,
}), nil
}
}
return ctx, errors.New("AUTHORIZATION_REQUIRED")
},
KeepAlivePingInterval: viper.GetDuration(config.WebsocketKeepAliveKey),
})
// ... // resolvers.go
func (r *subscriptionResolver) Notification(ctx context.Context, id string) (<-chan *model.Notification, error) {
appContext := middleware.ForAppContext(ctx)
if !oauth2.IsValid(appContext.Token) {
appContext.Cancel() // stop sending keep alive
return nil, nil
}
// ...
} I would love to have the ability to close the websocket entirely instead of hoping the client disconnects. In a way like this: // resolvers.go
func (r *subscriptionResolver) Notification(ctx context.Context, id string) (<-chan *model.Notification, error) {
appContext := middleware.ForAppContext(ctx)
if !oauth2.IsValid(appContext.Token) {
conn := middleware.ForWsConnection(ctx)
conn.Close(websocket.CloseNormalClosure, "unauthorized")
return nil, nil
}
// ...
} |
Beta Was this translation helpful? Give feedback.
-
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Beta Was this translation helpful? Give feedback.
-
Hello, I also have issues getting the authentication working with subscriptions. It works great for queries and mutations as it gets the token from the request header and stores it into the context of the resolver. Unfortunately, it doesn't work for subscriptions. Does anyone know why or how to get it working using the previously mentioned package? Thanks |
Beta Was this translation helpful? Give feedback.
-
You have to check authentication on init and store all you need in returned context. Then you can access this data and recheck authentication and authorization in your subscription resolver. This example should be very similar when using jwt. |
Beta Was this translation helpful? Give feedback.
-
@razorness I see. That actually makes sense after reading a bit more about the websocket protocol. Thank you :) |
Beta Was this translation helpful? Give feedback.
-
How Can I handle authorization in subscriptions? The current recipe is outdated. I managed to set authorization for queries and mutations. Can somebody point me into the right direction?
Beta Was this translation helpful? Give feedback.
All reactions