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

Implement prototype for handling multiple logins [WIP] #120

Closed
wants to merge 3 commits into from
Closed

Implement prototype for handling multiple logins [WIP] #120

wants to merge 3 commits into from

Conversation

Otto-AA
Copy link
Contributor

@Otto-AA Otto-AA commented Apr 17, 2019

I've changed the storage behavior to allow the storing of multiple login sessions.
Fixes #117

With these changes it's possible to login with multiple accounts (from different service providers for now) and make fetch requests to them. The different account credentials are stored in different locations in the localStorage (or other provided asyncStorage).
A short example running in the demo app:

// login with the popup login button...
// then paste this into the console
const popupUri = 'http://localhost:8606/popup-template.html'
const mySession = solid.auth.openSession('my-session')
mySession.popupLogin({ popupUri })

// ... login ...

solid.auth.fetch(privateFolderOfFirstAccount).then(console.log).catch(console.error)
mySession.fetch(privateFolderOfSecondAccount).then(console.log).catch(console.error)

Something I didn't manage to get working yet is to login with two accounts from the same provider (e.g. xyz.solid.community and abc.solid.community). I believe that the redirection here checks if you are currently logged in on this provider and, if yes, doesn't ask for your credentials again. But I didn't have much time to investigate that so I'm not sure. Here's where I think the error happens:
https://github.com/solid/solid-auth-client/blob/186236c5ebaa8b7f474f8f8ab3d38d15c06e101c/src/webid-oidc.js#L157-L159

I don't have time in the next days to work in this. So if you want, you can continue working on this in the meantime, or I will take it up again when I have time. And feel free to criticize anything :)

TL;DR

  • Separate storage for multiple accounts
  • Interface for handling multiple accounts (solid.auth.openSession(sessionId))
  • Allow multiple accounts of the same provider
  • Add test cases
  • Finish TODO's

@coveralls
Copy link

Coverage Status

Coverage decreased (-1.9%) to 81.18% when pulling 7d835e3 on Otto-AA:multiple-logins into 186236c on solid:master.

src/storage.js Outdated
@@ -105,3 +75,43 @@ export function ipcStorage(client: Client): AsyncStorage {
client.request('storage/removeItem', key)
}
}

export class StorageSession {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SessionStorage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is definitely better

@RubenVerborgh
Copy link
Contributor

Thanks, great stuff! I'm impressed. Some quick points below.

I believe that the redirection here checks if you are currently logged in on this provider and, if yes, doesn't ask for your credentials again.

True. You can force a logout though (which is what solid-auth-client will do if you call logout), and that logout should not invalidate the tokens.

The different account credentials are stored in different locations in the localStorage

Is your solution backward and forward compatible?

solid.auth.openSession

Maybe the session terminology is confusing. How about new solid.auth.SolidAuthClient or solid.auth.createClient? Then we assume that solid.auth is simply the default instance of SolidAuthClient (which is actually currently already is).

I am wondering a bit about how to name sessions/clients. How would you expect this to be used in practice? Would we really want to give them names, or just let people log in multiple times (and, for instance, identify by WebID)?

@Otto-AA
Copy link
Contributor Author

Otto-AA commented Apr 17, 2019

Thanks for your feedback, I will continue working on it when I find the time.

True. You can force a logout though (which is what solid-auth-client will do if you call logout), and that logout should not invalidate the tokens.

Are both of following logout requests used for this? (i.e. can I simply call the logout function in webid-oidc.js if a login is requested, but a different instance already is logged in with that provider?)
https://github.com/solid/solid-auth-client/blob/186236c5ebaa8b7f474f8f8ab3d38d15c06e101c/src/webid-oidc.js#L71-L76

Is your solution backward and forward compatible?

When switching, the current logins would be forgotten (could be changed by changing the default storage name).
Apart from that the only possible incompatibility I see is, that several functions (login, popupLogin, currentSession, logout) now ignore if a storage was passed as parameter. This potentially could has been used to supply a custom asyncStorage, but as far as I see it wouldn't be possible to use the fetch method this way (because it uses defaultStorage()). Therefore I don't see a reason why someone should do this.
I will look through the changes more closely next time to see if I find other important changes.

And I agree with you, that the naming is confusing.
I wanted to clarify, that openSession doesn't necessarily creates a new "session", but tries to open an existing one with that name, and if it doesn't exist creates a new one. That's why I went for "open" instead of "create" or "new". But I'd also be happy with new solid.auth.SolidAuthClient(...) as this makes it clear it's just another instance with the same type as solid.auth.

Regarding the IDs, I am not sure of the ways people will use it. The reason I did it that way is, to give apps the ability to differentiate between accounts which serve different purposes. With the id, they can hardcode the purpose into the id and always receive it that way. Without the id, they would need to associate the id and the webid and store this across sessions (e.g. localStorage, cookies).
A short example if this wasn't a good explanation:

const senderAuthClient = new solid.auth.openSession('sender');
const receiverAuthClient = new solid.auth.openSession('receiver');
// always send a file from the sender pod to the receiver pod

That's why I thought it could be convenient to specify an ID. Maybe it could default to the webId.
Something that I also thought about is to keep track of all stored logins and provide it via a method (e.g. getStoredLogins). This could be useful, if the app just wants to store an array of logins and then can fill it with all stored logins on startup.

@RubenVerborgh
Copy link
Contributor

Are both of following logout requests used for this?

Just the IDP logout should do.

When switching, the current logins would be forgotten (could be changed by changing the default storage name).

Let's do that 👍

several functions (login, popupLogin, currentSession, logout) now ignore if a storage was passed as parameter.

Just a note: might affect the popup (but you probably looked into that).

I wanted to clarify, that openSession doesn't necessarily creates a new "session", but tries to open an existing one with that name, and if it doesn't exist creates a new one.

We're creating a client, I'd say.

That's why I thought it could be convenient to specify an ID. Maybe it could default to the webId.
Something that I also thought about is to keep track of all stored logins and provide it via a method (e.g. getStoredLogins). This could be useful, if the app just wants to store an array of logins and then can fill it with all stored logins on startup.

I think this will be the most common scenario. I can't imagine the IDs really working for apps. (And if it does, they can keep their own internal mapping.)

@Otto-AA
Copy link
Contributor Author

Otto-AA commented Apr 22, 2019

Don't enforcing an ID as parameter makes it a bit trickier from my point of view. Here are some options I see:

Storage format

(1) Using webId as a key
This would mean, that the client needs to be able to handle the change of the webId (first login or logout->login) and hence the change of the storage key. Also maintaining an assoc of webId: {...data} in the localStorage seems necessary for getAllClients.

(2) Using an array
We could also store every login in a common array in localStorage (e.g. solid-auth-clients) and access them via their indexes. After a successful login it would store the login data in the first not-null element (or increase the size).

For both of these options, a temporary storage (sessionStorage or the memStorage) seems useful to store the state prior to the login.

Do you have any thoughts on this? I would tend to the second option.

@RubenVerborgh
Copy link
Contributor

The second option seems good, then we can offer the options as a set.

I was thinking that maybe we can do both:

  • key-based access
  • set access

So a key would be optional (but you can still use it if you want), and there is an additional option to get all the client instances.

That way, we don't have to predict how people will use the interface.

@Otto-AA
Copy link
Contributor Author

Otto-AA commented Jun 3, 2019

I've added the possibility to pass no id in the constructor. So new auth.SolidAuthClient(id) and new auth.SolidAuthClient() both work now. If no ID is specified it automatically generates a new (unused) one. It keeps track of the ids so all clients can be retrieved with await auth.getActiveClients(). But I am not sure what we should count as "active" client. I've implemented it to only return those which have a session stored (ie those who are logged in).

Just the IDP logout should do.

If we do it this way, people will have to reenter their credentials every time they are prompted to login. I think a good way would be to provide them a list of currently logged in accounts from which they can pick and a "Different account..." option. But that's likely a bit of work to do.

I didn't manage to get the tests working, so I didn't commit and push yet. If you want I can force a commit and push or send it as a zip(/...). I tried following to test but the jest tests failed:

git clone https://github.com/solid/solid-auth-client
cd solid-auth-client
npm install
npm test

Here are the test results as json: test.txt

I've tested it on localhost, but only the popup method worked (also with the original). It seems to work fine, but there are no automatic tests for multiple logins yet.

@Otto-AA
Copy link
Contributor Author

Otto-AA commented Jun 19, 2019

I still don't know how to fix these errors. I've just pushed it now so you can check it out locally if you want (or take a look at the Travis tests).

Base automatically changed from master to main February 24, 2021 17:50
@Otto-AA Otto-AA closed this by deleting the head repository Feb 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Handle multiple logins
3 participants