-
-
Notifications
You must be signed in to change notification settings - Fork 628
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
[Auth] How to re-request an operation with new context? #220
Comments
Sorry to bump this with a comment, but I would love if any of the contributors / maintainers could provide some direction here. I'm new to dart, so I might be missing something in how the Streams work. I would love to contribute to this project in terms of documentation or a PR if I'm able to get this to work. We're wrapping up work on our app soon, and this is the last major thing we have left to figure out, so any direction would be greatly appreciated! |
Have you tried stepping through the code using a debugger and see why the second request doesn't work. I will try and re-create your example when i get sometime tomorrow. |
I'll see if I can get that to work, but right now I'm struggling. I might just be misunderstanding the order that things get resolved, and how Streams work. I'll make sure to update here if I have a breakthrough! |
I think I'm getting to the bottom of this. I believe that the above code snippet actually works, and the operation is added back to the stream and requested again. However, I think that when the new operation resolves successfully, it is not triggering an update in I'm not 100% sure, but that's my best working theory right now. Does this sound plausible? If so, any ideas on what I might be able to do to get the |
@Kyle-Mendes Greetings, I got exactly the same issue. I currently can't understand why does the class which calls this API, doesn't wait for the listener to finish its work. So currently, after |
@Kyle-Mendes Aha, I just reviewed your last comment. Seems like we are at the same point. @mainawycliffe I guess the problem here, is that
|
@mainawycliffe Can I please get some help on that? What else can I do to help you investigate that? |
@Nazacheres this slipped my mind, I have yet to implement similar functionality, so I don't have a working sample but I will investigate and report back over the weekend. If you can share a reproducible sample repo, it would really save some time. @Kyle-Mendes did you ever find a solution, and if so can you please share. |
I did not find a solution yet. I am still unable to get the widget to re-render when my added stream completes. We did a little work-around for now, though. We added to the |
@Kyle-Mendes So on each request, you check if the token is correct? Do you do it by decoding the token and calculating the time, or making an additional request? |
@Nazacheres For our API, we get back an It's not ideal, since tokens can expire for other reasons, so a true solution using the |
@Kyle-Mendes I am currently working on another workaround will let you know till the end of tomorrow. Thank you for your help. |
@Kyle-Mendes I managed to fix it! My understanding of streams in dart probably far from perfect, however here is my solution based on how I imagine streams working. This is my whole custom link:
And here is method refreshToken:
As you can see instead of forwarding request, I am forwarding custom future (which then is converted to stream).
and it throws ClientException, not graphql error. However this is the concept how I managed it to work for me, if you guys @Kyle-Mendes and @mainawycliffe see how this can be improved please let me know. |
@Nazacheres can you create repository with working sample, if your code actually works? |
Did anyone find a solution to the @Kyle-Mendes 's problem? |
For anyone still looking for pre-made solution: The fresh_graphql package seems to be updated to use flutter graphql v4: https://github.com/felangel/fresh/tree/master/packages/fresh_graphql Depending of your use case it might work out of the box, and if not, you should be able to tune it to suite your needs. The link implementation looked pretty straightforward. Have not tested it though, since managed to get refresh to work by using Dio as a http client with the gql_dio_link. Dio 's interceptor middlewares are little bit simpler to implement and they allow queuing (locking) new requests and response error handling that makes sure only one refresh-request is made simultaneously and new graphql requests can wait for the refresh before trying. That is however extra nice stuff that you might not need. |
Hello @jamonkko would you kindly share with us your refresh implementation using Dio as a http client with the gql_dio_link fresh_graphql didn't work out for me I've had to many issues with it |
@Aristidios you can find some code examples how to do it with dio interceptors from there cfug/dio#50 Note that the earliest examples in that issue require small porting to latest Dio v4. There seems to be some posts in that thread how to fix that too. You can also google for "dio interceptor token refresh" which will yield multiple promising hits for more examples. One thing that might not be in the examples is that even if you lock new requests from being sent while refreshing the token, you still might initially send more than one requests concurrently that will all fail with 401, in that case the example code will probably make multiple jwt refresh calls. To avoid that you would need to somehow throttle the refresh requests e.g. by a shared future to hold refreshed jwt which also tracks if refresh call is already on the way. That will make the code more complex though and might want to think if that is needed or not. |
Hey can anybody share their example of refresh token with locking the request and response thread similar to Dio. Thanks! |
You can also actually do what @Gujie-Novade mentions in #672 which is to use a custom final AuthLink authLink = AuthLink(
getToken: () async {
final token = await getAccessToken();
return `Bearer $token`
},
);
...
void getAccessToken() {
// retrieve the access token from wherever you stored it
// parse it and check the expiry
// if it's expired, renew it by making a HTTP call to your server with your refresh token
// return the access token
} That way you don't even need to get a 401 back since you know whether the access token expired already or not, to your app it will seem as though everything is as it normally is when using a non-currently-expired access token. |
@satvikpendem what if token expired during request (401) and we have to refresh current token (with refresh token and get new one and continue the request) ? how do we do that in |
@satvikpendem I don't think that works when you have multiple requests failing at the same time due to expired token though, as they'll all try to call the |
I'm trying to write my own
AuthLink
to allow me to handle expiredaccess_token
s and refresh them. In the ideal implementation, I would try the request again, like in Apollo.In Apollo I'm able to use the
onError
link to just callforward(newOperation)
after passing the updated headers. This will pass the operation along and request it again.I tried implementing a similar approach in our flutter project, and I think I'm pretty close.
I correctly catch when the
operation
fails, but I'm not able to get the operation to fire again. My approach was to callawait controller.addStream(forward(operation));
after callingoperation.setContext
to update the headers. This doesn't work, though. All future GQL requests will succeed, but the initial request that failed will not fire again unless I trigger the operation again.It might be because
Request
is already filled in on theoperation
but, I'm not sure.The text was updated successfully, but these errors were encountered: