-
Notifications
You must be signed in to change notification settings - Fork 13
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
Feat/call check for revocation #1372
Conversation
BREAKING CHANGE: checkForRevocation() is only callable when dealing with an OAuthClient. It should not break your app, since if you called this method on a stackClient before, it should have crashed your app.
@acezard I would have add a test for the scenario:
|
In some cases the promise rejection is not handled at all by refreshToken, since it was not really clear what was happening it seemed safer to add an early check
@Crash-- test added, from my side everything seems good but I'm not sure I'm receiving the expected messages on revocation (with a registered client). But it still works with any error on refreshToken, we'll always do an early check |
) | ||
// Have to catch early to check for revocation because it seems the error is not caught by the catch below in some cases (e.g. when the client is not registered, even if it should be) | ||
.catch(async e => { | ||
if (await this.checkForRevocation()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Y a un truc que je comprends pas :
- déjà ce catch pourquoi il doit être de cette forme plutôt que le catch plus bas ? 🤔
- le checkForRevocation fait un fetchInformation, qui lui même throw déjà une erreur
throw new NotRegisteredException()
. Du coup pourquoi avoir besoin de lever cette erreur plutôt que celle déjà levée?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
je n'ai pas réussi à trouver la source du problème mais sans le catch chained, certaines erreurs (dont celle qui m'intéressait pour être revoked) n'étaient tout simplement jamais catch, comme si elles étaient catch ailleurs. En chainant le catch à la promise, le problème ne s'est jamais présenté à nouveau
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK ça c'est le premier point, et le second ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK ça c'est le premier point, et le second ?
le second, c'est que justement si je me révoque depuis settings web, la première erreur que je reçois est un "client not found", alors qu'effectivement si je comprends bien je devrais avoir un Invalid token. Mais ce n'est pas ce que m'envoie la stack en master last commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pourquoi tu penses que tu devrais recevoir un invalid token? On l'a déjà reçu en premier lieu, ensuite on fait un fetchInformations() qui va vérifier si justement le client existe. De là ça va throw puis passer ici https://github.com/cozy/cozy-client/pull/1372/files#diff-7818881da36e23a808dace9ce34c92ea922a6151ef1a65b66c10667bcf3660bdR678 et donc appeler le onRevocationChange. Mais l'erreur que tu vas recevoir c'est effectivement client not found.
C'est pas logique ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non le corps de la réponse contenait déjà the client must be registered
. Mais cozy-client
se base sur la valeur du header www-authenticate
pour déterminer le message de la FetchError
normalement (voir https://github.com/cozy/cozy-client/blob/master/packages/cozy-stack-client/src/errors.js#L56).
En tous cas c'est ce qu'il se passe dans mes essais.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anc@desktop:~/cozy/cozy-client$ curl -v -X POST 'http://dev.192-168-1-65.nip.io:8080/auth/access_token' -H 'accept: application/json' -H 'Accept-Encoding: gzip' -H 'authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhY2Nlc3MiLCJpYXQiOjE2OTAyOTAwNDUsImlzcyI6ImRldi4xOTItMTY4LTEtNjUubmlwLmlvOjgwODAiLCJzdWIiOiJlZDczY2E0Njc0MmZhNjliMWM2ZDAzZDI4MDUxY2U4MyIsInNjb3BlIjoiKiJ9.0s-LzKsemSlJkPllcNyw0QfZ_ve2ux9xKcsQaH2S8aQv8QFP0InJTf1GRmGZok7iUdBUJSEgeyPnoXNLIrsPRw' -H 'Connection: Keep-Alive' -H 'Content-Length: 419' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Cookie: _csrf=JmInvLRunjQDXYKLSFWSejcXXoBKEmlY; cozysessid=AAAAAGS_xAJlZDczY2E0Njc0MmZhNjliMWM2ZDAzZDI4MDUxNGM1YQ-b1cz6d-rpHyWKDLvo0iP15IKfE5UI7G1D7nhTC6qO' -H 'Host: dev.192-168-1-65.nip.io:8080' -H 'User-Agent: io.cozy.flagship.mobile-1.1.10' -d 'grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZWZyZXNoIiwiaWF0IjoxNjkwMjkwMDQ1LCJpc3MiOiJkZXYuMTkyLTE2OC0xLTY1Lm5pcC5pbzo4MDgwIiwic3ViIjoiZWQ3M2NhNDY3NDJmYTY5YjFjNmQwM2QyODA1MWNlODMiLCJzY29wZSI6IioifQ.U7dTHg385sJyTiSBVICWHWNEJX5M0mWFgC5a_ye8ZrYWSEb_SIaH5rBzgndrTPADYIc-dXK40pJokamTj7VUoA&client_id=ed73ca46742fa69b1c6d03d28051ce83&client_secret=83ynXwyla94mWHtYiSzP-sFia5FPZ2nS'
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 192.168.1.65:8080...
* Connected to dev.192-168-1-65.nip.io (192.168.1.65) port 8080 (#0)
> POST /auth/access_token HTTP/1.1
> Host: dev.192-168-1-65.nip.io:8080
> accept: application/json
> Accept-Encoding: gzip
> authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhY2Nlc3MiLCJpYXQiOjE2OTAyOTAwNDUsImlzcyI6ImRldi4xOTItMTY4LTEtNjUubmlwLmlvOjgwODAiLCJzdWIiOiJlZDczY2E0Njc0MmZhNjliMWM2ZDAzZDI4MDUxY2U4MyIsInNjb3BlIjoiKiJ9.0s-LzKsemSlJkPllcNyw0QfZ_ve2ux9xKcsQaH2S8aQv8QFP0InJTf1GRmGZok7iUdBUJSEgeyPnoXNLIrsPRw
> Connection: Keep-Alive
> Content-Length: 419
> Content-Type: application/x-www-form-urlencoded
> Cookie: _csrf=JmInvLRunjQDXYKLSFWSejcXXoBKEmlY; cozysessid=AAAAAGS_xAJlZDczY2E0Njc0MmZhNjliMWM2ZDAzZDI4MDUxNGM1YQ-b1cz6d-rpHyWKDLvo0iP15IKfE5UI7G1D7nhTC6qO
> User-Agent: io.cozy.flagship.mobile-1.1.10
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=UTF-8
< Date: Tue, 25 Jul 2023 13:09:16 GMT
< Content-Length: 42
<
{"error":"the client must be registered"}
* Connection #0 to host dev.192-168-1-65.nip.io left intact
curl de mon POST access_token pour ref. Je n'ai pas l'impression qu'il y ait le header www-authenticate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pour info, dans mes tests, Desktop faisait une requête sur /settings/disk-usage
.
C'est cette requête qui recevait une erreur Expired Token
déclenchant un refresh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Je viens de tester à nouveau et effectivement cozy-client
ne voit cette erreur ni comme un Expired Token
ni comme un Invalid Token
parce qu'elle utilise le corps de la réponse comme reason
.
@acezard I'm wondering if it would be easier to read the PR with integration tests that mock only the I did that in another PR and it has the advantage of making easier to vizualize the different scenario and what are the cozy-stack answers: |
I agree on principle, but from my tests in runtime, the stack didn't send what I expected. Thus, I preferred to assume the end result of the calls, not the stack answers. But I agree that I don't like mocking internal methods in a test |
f515e75
to
5e198d2
Compare
}) | ||
return newToken | ||
} catch (e) { | ||
if (errors.UNREGISTERED_CLIENT.test(e.message)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not using this.isRevocationError
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but then we need to update it because currently it only tests for const CLIENT_NOT_FOUND = /Client not found/
. I'm on it
- Updated
this.setToken(newToken) | ||
throw new Error( | ||
'Client has been revoked or does not exist. Please authenticate again.' | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if we should change the error message. Shouldn't we throw the real error? Or a fetch error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well yes I guess I wanted to imitate the checkForRevocation conditional
const revoked = await this.checkForRevocation()
if (revoked) {
throw new Error('Client has been revoked. Please authenticate again.')
}
I'm not sure if it's still a fetch error at this point, it's more a reaction to a fetch error. But we could indeed at least keep the error message and add more info saying that error message probably happens because client was either revoked or doesn't exist (both can be true)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Updated
|
||
return newToken | ||
if (revoked) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, I think that checkForRevocation() should throw the real error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, then the initial fetcherror? as I mentioned earlier, I think we should add some more context info maybe. Like adding we think the client is revoked (I mean it's 100% sure it doesn't exist, but it's either revoked or non-existing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Updated
* | ||
* @async | ||
* @returns {Promise<boolean>} A Promise that resolves to `false` if client is still valid, or `true` if it has been revoked. | ||
* @throws {Error} If an error occurs while fetching the client information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this implementation, this is not true, but we should throw https://github.com/cozy/cozy-client/pull/1372/files#r1274467375
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, it's fine by me I think both throwing a generic error or the initial fetcherror is fine as long as some context info is added during handling of the initial error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Updated
dc3bc1a
to
ecae5a2
Compare
* | ||
* @async | ||
* @returns {Promise<boolean>} A Promise that resolves to `false` if client is still valid, or `true` if it has been revoked. | ||
* @throws {FetchError} If an error occurs while fetching the client information. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method doesn't throw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Crash-- updated
6a56c15
to
6d9303a
Compare
6d9303a
to
3899557
Compare
When we got an error for OAuth token, we check if it's something that can be used for revokation. If yes, then we make a call to know if the client is revocked or not.