Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do you manage the refreshed access token? #774

Closed
sneko opened this issue Jul 3, 2019 · 5 comments
Closed

How do you manage the refreshed access token? #774

sneko opened this issue Jul 3, 2019 · 5 comments
Labels

Comments

@sneko
Copy link

sneko commented Jul 3, 2019

Hi everyone,

I'm currently blocking invalid access tokens passed through connectParams inside the websocketInitFunc (v0.9.1) but this is done once at connection.

On the user side, when its access token expires, the application will automatically request a new access token with the refresh token. Great but now I have no "official" way to give it back to my GraphQL subscription API. It means that once connected my user is authorized forever unless the websocket connection is cut.

How do you manage that? I thought about sending a specific message over the websocket connection from the frontend so the backend can update the init payload (connectParams) by setting the new access token. But it seems a bit hacky 😢

@eddeee888 thank you for the #750 . Maybe do you have already figured it out?

Thank you,

@sneko
Copy link
Author

sneko commented Jul 8, 2019

I'm considering creating a subscription RefreshToken($token) in addition to my standard mutation.

Like that when the application refreshes the token through the mutation and gets the new access token, this one subscribes to RefreshToken($token) by passing the new token. Then the subscription callback parse the new parameter token and modify the initPayload stored inside the context.

I'm a bit surprized no one has encoutered this problem? Did I miss something? I would be interested in having your thoughts about that @vektah 😄

BTW, I'm using the RefreshToken($token) subscription to be sure it's directed to the right API (in case I have multiple instances of the API).

EDIT: another solution is described there apollographql/apollo-link#197 (comment) but I'm not sure it can be easily applied to gqlgen server side?

@stale
Copy link

stale bot commented Sep 6, 2019

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.

@stale stale bot added the stale label Sep 6, 2019
@stale stale bot closed this as completed Sep 13, 2019
@leebenson
Copy link

FWIW, we handle this in the client. If a JWT changes locally, the WebSocket is closed. The client we use (Apollo) has a reconnect: true option, so the next time a subscription is requested, it uses the new JWT.

This has the side-effect of canceling any active subscriptions, so YMMV with this approach. For us, it's fine, because a changing JWT normally indicates a user has explicitly logged out and logged back in, so existing subscriptions would likely stop anyway.

@RobinCPel
Copy link
Contributor

For anyone who is still looking for a solution, it should now be possible with a websocket init function like so:

func WebsocketAuthInitFunc(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
	payloadAuth := initPayload.Authorization()
	if payloadAuth == "" {
		return ctx, errors.New("the auth token is missing in the initialization payload")
	}

	// Verify that the token has the correct access rights
	token, err := authenticate(payloadAuth)
	if err != nil {
		return ctx, err
	}

	// Add the token expiration as a deadline and append a close reason to the context values that will be send to the client before the websocket actually closes 
	// (Also throw away the cancel function, which the linter does not like)
	newCtx, _ := context.WithDeadline(transport.AppendCloseReason(ctx, "authentication token has expired"), time.Unix(token.ExpiresAt, 0))
	return newCtx, nil
}

Note that at the moment of typing this, this functionality is not included in a release yet (only on master).

@sneko
Copy link
Author

sneko commented Jan 26, 2022

@RobinCPel thank you for your PR! It does the job perfectly!

Just one of my tips:

Note: we subtract a few seconds to be sure the connection will be closed before expiring, so at expiration time no subresolvers will reach our services with an expired token
This is possible because our frontends refresh the token minutes before it expires to ensure reaching our endpoints fully. If the frontend is not set like that, making it reconnects a few second before would probably send the expiring token on the new connection... not helping that much and making it retrying multiple times until the frontend has really the expected new token

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants