-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Allow logout with invalid session #7277
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
Comments
Definitely can cause an issue on the client side. I did a fix in parse-community/Parse-Swift#73 which essentially clears the user from the Keychain ignoring any server errors (code): public static func logout(options: API.Options = []) throws {
let error = try? logoutCommand().execute(options: options)
//Always let user logout locally, no matter the error.
deleteCurrentContainerFromKeychain()
BaseParseInstallation.deleteCurrentContainerFromKeychain()
BaseConfig.deleteCurrentContainerFromKeychain()
//Wait to throw error
if let parseError = error {
throw parseError
}
} |
Thanks @cbaker6 for your example, that's interesting because obviously a different error could occur here too. My thoughts are that if an invalid session is provided to the logout request, it should return with a "success" so current user can be cleared internally, and developer can redirect to login screen. It would just mean logout cloud triggers wouldn't fire for invalid sessions, as there would be no way to tell who the "real" user is who making the request is. What do you think? |
That sounds good to me because it seems the user is "attempting" to discard their current session token by logging out. If the server does what you mention, then the other client SDKs wouldn't have to implement something similar to what I have above. The only issue they would run into is if a different error from the server occurs. |
Looks like we were thinking the same thing! |
Interestingly in the JS guide it recommends calling |
It seems if the JS SDK isn't doing something similar to ParseSwift, the user will get stuck in limbo unless there's another method JS provides to clear the Keychain. Or, delete the app as you suggested... |
This should be handled by the client application. Making the server "lie" about the result of an operation prohibits the client SDK or client application to perform more complex flows, depending on the specific server response. We discussed a similar issue in https://github.com/parse-community/parse-server/security/advisories/GHSA-cfgm-jqhh-xmhr#advisory-comment-64808 and came to the same conclusion. The communication between the server and the SDK should be truthful, the communication between the SDK and the client application as well. The communication between the client application and the user can be as opaque as the developer prefers and needs for their use case.
This seems to be the actual bug the needs to be addressed, and maybe in other SDKs as well. |
So you would suggest catching the error in the logout request in the JS SDK? |
I suggest that the SDK properly cleans up the cached current user (if that makes sense technically), but reports to the client application truthfully, that the logout failed. It is up to the developer to catch these errors and deal with them, not up to the SDK to "lie" about the outcome of an operation in my opinion. As I understand it, the logic that is mentioned above for the Swift SDK is the correct approach, it clears any internally cached current user (which the SDK needs technically), and truthfully throws the error to the client application. |
So, if I have: await Parse.User.logOut();
window.location.href = '/login'; Would I have to wrap that in: try {
await Parse.User.logOut();
window.location.href = '/login';
} catch (e) {
if (e.code === 209) {
window.location.href = '/login';
}
alert(e.message);
} |
Yes. And this allows another developer to not redirect to |
Infact, that's how the code functions as is: it('can logout with expired session token', async () => {
await Parse.User.signUp('asdf', 'zxcv');
const sessionQuery = new Parse.Query(Parse.Session);
const session = await sessionQuery.first({ useMasterKey: true });
const database = Config.get(Parse.applicationId).database;
await database.update(
'_Session',
{ objectId: session.id },
{ expiresAt: new Date().setFullYear(2010) },
{}
);
try {
await Parse.User.logOut();
fail('should have returned invalid session');
} catch (e) {
expect(e.code).toBe(209);
expect(Parse.User.current()).toBe(null);
}
}); It's my opinion that this is still a little clunky, and perhaps a |
Also the docs might need to updated to: function handleParseError(err) {
switch (err.code) {
case Parse.Error.INVALID_SESSION_TOKEN: {
try {
Parse.User.logOut();
} catch (e) {
if (e.code !== 209) {
handleParseError(e);
}
}
... // If web browser, render a log in screen
... // If Express.js, redirect the user to the log in route
break;
... // Other Parse API errors that you want to explicitly handle
}
}
// For each API request, call the global error handler
query.find().then(function() {
...
}, function(err) {
handleParseError(err);
}); |
How so? You mean because it is throwing but still clearing the local current user? |
If you're using an app, and all your errors are "your session has expired", you would think "ok, I need to log back out". Then you go and click "logout", and unless the Parse developer is aware of the way logout works with invalid sessions, you get the error message "your session has expired" (which you already know - that's why you're logging out). I would assume that most developers aren't catching specifically for error code 209 in their logout calls, which I could imagine would lead to frustration with end users. I know I wasn't. Maybe this just requires a doco improvement. |
The actual inconsistency for me is that the local cache is cleared if I see three possible approaches:
I would go with a) unless we can think of any reason why a user should stay locally logged in although the authoritative entity (Parse Server) says the token is not and will never ever become valid again. Now I can think of a use case where an app is offline, the user does some operations, then the app goes online and the server responds with |
I'm not sure if that's the case. I've been trying to figure out how it works in the JS SDK.
Theoretically a developer could temporarily store the invalid user alongside the cached operations and ask the user to confirm the tasks once the session is revalidated. You're right, fundamentally changing the way this works could cause some unintended side effects. Again, most of the documentation states:
I guess in the case of option 1, the could still pin objects to LDS with an invalid session? Perhaps there's no need for any change on the server. I probably still haven't explained properly but by clunky I mean it's sorta unintuitive that to handle invalid sessions, we recommend calling So, I think the existing behaviour is fine, we just need to change |
We could also add something to the SDK such as |
That sounds like approach b) and it seems to be a clean approach because it separates the Another thing to consider are server side hooks like
Yes, that's a possibility. I suggest to evaluate what most developers would need and intuitively assume, define the default behavior and what should be configurable and see what changes are needed. For example, is this option you mention really something needed on request level, or does it make sense to define it in the SDK config whether to clear the session token on |
Closing as I see this more as a JS SDK discussion. Will reopen and continue discussion shortly. |
New Feature / Enhancement Checklist
Current Limitation
Currently, if your session token becomes corrupted, even logging out returns "invalid session token", or "Session token is expired", meaning for most users there's no way to resolve this issue without force quitting / reinstalling.
Feature / Enhancement Description
Invalid Session Tokens shouldn't prevent users from logging out and
Parse.User.current()
from clearing. Even with an invalid session,logout
should allow users to re-login.Example Use Case
Alternatives / Workarounds
3rd Party References
Discussed here
The text was updated successfully, but these errors were encountered: