I give a flow of things that’ll happen in the model I propose.
1 User provides Diaspora ID to the app.
2 App contacts the user pod, provides the username, access scopes necessary, and developer (author) id (Diaspora ID of the developer) . Redirect user to login page.
3 User gives her username and password and agrees to allow the application to access her data. Access scopes the app requested are displayed to the user.
4 Application is granted an refresh token which is sent to the developer’s pod encrypted for the developer. app must have the ability to securely retrieve the token from the developers pod.
This model uses the developer ID as the trust anchor, refresh tokens (which are temporal, lasting for a limited time) are used to get access tokens.
Use access scopes to define what apps are allowed to do on users data.
Note: This discussion was imported from Loomio. Click here to view the original discussion.
This is OAuth, isn’t it? @jonnehass and I were talking at length one Saturday morning (well, it was morning for me anyway) about the best way to accomplish this. We aren’t too comfortable with putting all application trust in the developer. Instead, we were considering a solution that shifted that level of trust to the user running the app. So users have complete control over app access to their account.
IIRC, the idea was that each API client (“app”) would receive an encrypted key (that the developer can not see) and such a key would be verified every time the user wanted to get secure data from the pod.
This would basically allow any app that speaks “Diaspora API” to connect with any pod, as long as the user on that pod has authorized such access.
Yeah, i guess this is oAuth. What I wanted to learn is the possibility of using developers id as the trust anchor. And I have talked with @jonnehass briefly about trust on the user, and would really like to know more about that model.
I and a set of buddies of mine would actually like to implement an authentication model for third party apps for diaspora. That’s why I am seeking information.
So these keys the API client receive, do they receive it from user’s pod? “such a key would be verified every time the user wanted to get secure data from the pod.” I don’t really get this part. every time the user wanted to get secure data?
@arunaherath i guess it’s kinda like a browser cookie. you send some auth data to the server, and it sends you back a key of some kind if that auth data matches up to some user. all of the secure data encryption is done on the client side, then the client tells the pod what its key is, and the pod logs that information down. every subsequent time the client connects, it checks its key with the stored key on the pod. logging out is deleting the local cached copy. you should also be able to revoke access to any app on all (or some) of your devices via the pod’s web interface.
pop in to IRC some time and either me or MrZYX would gladly talk your ear off about this idea
oAuth puts trust into the application itself, less into the developers of it. My main point is, since we can’t have a central registry, we can’t trust the app. Instead we need to move the trust anchor somewhere else, where needs to be discussed.
Linking a developers Diaspora account to the app gives the user a reference to follow, to audit the trustworthiness of the app. It doesn’t provide a trust anchor on its own, that responsibility stays still at the user.
Securely linking the app to a developers account is easy, we got a keypair for the account already, so all we need to do is signing the metadata of the app with the private key. This signed manifest can then be posted to a pod when doing the authorization dance, the pod can fetch the profile of the developer, verify the manifests signature and display the user a link to the profile.
The signing of the manifest can either happen as a upload/download service inside Diaspora or as a separate application. In the later case we just have to give a user the ability to download his keypair.
A quick overview of the authorization process could look as follows:
- The user enters his Diaspora ID into the application
- The application obtains the hostname from it
- It does a POST request to hostname/dauth/manifest with his signed manifest, he gets a one time authorization token back.
- The pod (temporarily) stores the generated token as well as the data in the manifest.
- In case of a webapp the manifest contains a URL to redirect back to
- In case of a webapp the application now redirects the user to hostname/dauth/authorize/authorization_token
- In case of a native client it just opens a browser to that URL.
- If the user has no valid session he’s redirected to the sign in page and redirected back to the authorization page after having successfully signed in.
- On the authorization page he can now review the requested scopes, maybe dynamically uncheck them (we could think about making a scope required/optional) and more importantly review the developers profile.
- If the user denies the authorization:
- In case of a webapp he’s redirected back to the URL specified in the manifest, with an additional parameter set, indicating a failed authorization.
- In case of a native client a JSON response indicating the failed authorization as well as an appropriate HTTP response code is set. The native client is expected to catch any response and to not present it to the user.
- If the user approves the authorization:
- The pod keeps the manifest and generates a refresh token, this is the main token granting the application access to the users data. The manifest and the refresh token are associated. The refresh token is also associated to the user. The user has an interface to review the refresh tokens, the granted scopes and the associated developer profile are displayed alongside. The user can revoke refresh tokens here.
- In case of a webapp: The pod redirects the user to the redirect URL specified in the manifest. It adds a parameter handing over the refresh token.
- In case of a native client: The pod generates a JSON response containing the refresh token. Again the client is expected to catch the response and to not present it to the user.
- The application does a request to hostname/dauth/access_token?refresh_token=obtained_refresh_token. The pod answers with a JSON response containing an access token with a limited lifetime (not much more than a day). The pod stores the access token and associates to the refresh token.
- The access token can be used to make calls to the rest of the API.
An optional extension to that process follows:
Application specific password extension:
The user can use the UI to generate refresh tokens that have no manifest associated but a list of allowed scopes. The token is displayed to the user easily copy-pasteable plaintext as well as a QR code. This refresh tokens can be used by more than one application to gain access tokens. In this case generating an access token must not invalidate other valid access tokens associated with the refresh token.
Yes, this is simplified oAuth. But I don’t think we can’t get it easier without just doing user requested token authentication. Basically just the extension then. oAuth has become what it is because it increased the convenience for the user. But that comes at the cost of complexity.
@tomscott @arunaherath and I are already talking quite a lot with each other over IRC
I haven’t read the discussion in detail (haven’t the energy at the moment), so apologies if this misses the mark. But can we put the onus on each user to satisfy themselves of the ‘okayness’ of each app before they sign up to it? For example by flagging a warning ‘Diaspora cannot vouch for the authenticity of any app. Please ensure that you are happy to share your data with the authors of this app before proceeding.’
That way, each person has to take responsibility for the use of their data, and assuming that security on pods is good enough that no one could use this connection to hack into other people’s data, there’s no problem.
As I say, apologies if this doesn’t address the issue at hand, but it’s what came to mind when I scanned the thread, and what I think you’re talking about, albeit a non-technical way to approach the problem.
@goob Really sorry about responding this late. It is too early to discuss surface behavior imho. But it is definitely possible to do what you say.
Thank you very much for the detailed explanation @jonnehass. We have been studying about rails and diaspora codebase and oauth providers. I believe it is ok to give this a try and implement what we can. So as a start we prepared this database structure(google doc) for our oauth (or dauth) provider. I’ll be thankful if you guys can take a look.
Looks alright from a quick look, I see no deep conceptual misunderstandings at least. The specifics will prove when implementing
Thanks @jonnehass. That’s what I thought as well :), we’ll go ahead and implement and see what happens.
Here is the current implementation of above discussed authentication model. We are waiting for code review and comments to move forwards. Please share your opinions to improve this authentication model
@akilairoshan Wow thanks +1
@akilairoshan it might be worth posting a reminder that you’re waiting for code review on that Github issue in the hope that someone competent to do so (which, I’m afraid, I’m not) can look at it.
Now that there is a $400 dollar bounty on implementing an API, I think it would be a good idea to decide on what would be an acceptable implementation for creating an API. As everyone knows, the tricky part is not making the API itself, but getting the authentication system done.
The previous work here specced out by @jhass and worked on by @arunaherath didn’t complete, so I guess we are looking at other options - or would we still want this spec to be the baseline for an implementation?
Personally, I think we should keep it as simple as possible. I’m not sure we need to tackle scopes and manifests and so on in the first version. Just a simple “full or none” access to the account. The API feature set is likely to be very limited anyway to start with. Build tiny things, then iterate.
Anyway, I think @jhass was also looking into OpenID at some point? How would that work, I assume the idea is that each pod becomes an OpenID Connect provider? Here is the most recent Rails gem I found: https://github.com/nov/openid_connect
Would it be possible for us to lock some “would be accepted” spec regarding the API authorization model so that we can say at least “hey here is the issue feel free to work on it”. Right now it’s “hey here is an issue but please don’t work on it even though people have paid $400 since we don’t have a spec”
Yes, back when I wrote the above up, OpenID Connect was not released yet, these days we should just implement it.
Yeah, I definitely think OpenID Connect is likely the best way to go at the moment. It might be worth taking a look at the Ruby OpenID Connect gem.
Hi guys. Just providing some informations to keep the community in touch. I’ve started to play with the OpenID Connect gem inside a mock project. For now, I managed to go through the beginning of the OpenID classic handshake, that is, the 2 first steps on the following official diagramm:
I also took a look at the way to integrate smoothly with the existing management system which is Devise. If I’m not wrong, Devise uses OmniAuth, which has an OpenID plugin. So, things are going the right way.
Anyway, I’ll continue to give informations regularly on that post.