storacha / w3up

⁂ w3up protocol implementation
https://github.com/storacha-network/specs
Other
57 stars 19 forks source link

Authorization flow #723

Open Gozala opened 1 year ago

Gozala commented 1 year ago

Our current authorization flow is not great, because:

  1. First agent gets to own the space which could be a problem if that agent isn't supposed to.
  2. It adds significant complexity for an app, because they can't simply request access they need to function, they have to detect if space needs to be created, then create it and also delegate capabilities back to account. There are just too many mistakes that can happen that would lead to bad experience downstream.

So here is what I had been imagining instead with a goals of:

  1. Design around principle of least privilege (POLP)
  2. Simplified dev experience (app just asks for things it needs to function on demand).
  3. Simple & straightforward UX.
  4. User has complete authority

Here is what I imagine in terms of flow

  1. Every invokes access/request specifying capabilities it requires to function (on demand).
    • Audience of this request is did:mailto: derived from user specified email address.
  2. When we receive access/request for some did:mailto: we resolve account email & derive temporary session principal that can act on behalf of account.
    • We generate random 5 digit pin code (which can be rendered as android lock pattern)
    • We combine account email address and generated into a seed from which we generate ed25991 key.
    • We delegate * from account to session principal (valid for 15 mins) & associated attestation from us (which we persist with access/delegate)
    • We delegate consumer/add capability to the account DID (if we already have it it's a noop)
    • We forward received access/request and generated pin to an account email address
      • Email will contain link to access confirmation page with email and access/request encoded as query params.
  3. User receives an access requesting email
    • It contains rendering of pin code as android lock pattern
    • It contains a link to the page that can be used to grant authorization
  4. Clicking link in email takes them to the static authorization page
    • Page extracts email from query param and derives account did
    • Page renders android lock pattern asking user to draw it
  5. After user draws android lock pattern
    • Page derives session principal from pin + account did it extracted from query param
    • It uses derived session principal to run access/claim in order to get delegations allowing it to act on behalf of account did.
    • It then fetches account capabilities using access/claim with account DID.
    • It extracts original access/request and renders UI allowing user to grant / select matching capabilities that account has.
  6. User chooses capabilities from the rendered UI to grant them to the agent
    • If account has no matching capabilities page either offers to create a new space which it can do using delegated consumer/add.
      • In this case new space keypair is generated and provisioned
    • User chooses space (if there are multiple qualifying ones) and clicks "grant" button
  7. When user clicks "grant" button
    • Pages issues access/request receipt with account DID and user selected capabilities.
    • Pages sends access/grant with an ☝️ receipt to us.
  8. When we receive access/grant capability
    • We create a delegation from account did to the agent with capabilities in the receipt and corresponding attestation.
    • We store delegation using access/delegate.
  9. When agent fetches delegations it gets requested capabilities

I know this is complicated, but it is complicated for us and not a user or a app dev. Let's also look how this achieves stated goals

  1. Design around principle of least privilege (POLP)

App/Agent only gets privileges that user has selected regardless if user had an account and a space yet or not.

  1. Simplified dev experience (app just asks for things it needs to function on demand).

App/Agent never has to worry about spaces they just request some capabilities and receive them if user grants them. They don't have to ask user for email or anything ahead of time they just do it on demand. Although we may want to remove email loop on repeated requests.

  1. Simple & straightforward UX.

User clicks link in the email and either clicks "grant" or "create space" and then "grant".

  1. User has complete authority

Notice that at every step user is in charge. We derived session keypair and send a link to our authentication page however user could use alternative if they so choose because it's just pin code and account from which all is derived. In other words user could use e.g. native app or a third party app that will do all the steps that our authentication page does.

Also notice that while we have access to the session keypair it has only authority to act on behalf of account for 15mins which is just enough to complete the authorization flow. If that keypair leaks after that time there is no consequences as it does not stay in delegation chains.

travis commented 1 year ago

This all makes sense to me! Couple nit-ish questions about the pin code stuff:

It contains rendering of pin code as android lock pattern Page renders android lock pattern asking user to draw it

I can't quite tell what we're trying to accomplish with this pin code - there are a couple possible UX goals I can think of:

1) to provide the user with assurance that they are receiving a legitimate email auth request 2) to provide us (the service) with assurance that the person confirming an email auth request is the person who initiated it (ie, in w3cli or an app using w3ui)

If I'm reading the above correctly the pin is for (1) in this case - we send the pin in the email and then ask the user to draw it to make double sure that they've paid attention to it - is that correct?

I'd like to at least talk through the potential benefits of (2) above - I think the only difference from what you've described above is that we would not include the PIN in the email we send to the user. By requiring them to provide it separately we'd have a fairly strong guarantee that the user clicking the link in the email and granting permissions is the person who initiated the capabilities request process in w3cli or w3ui, which would give us a fairly strong justification for sending the delegations to that user.

Does this sound right or am I missing/misunderstanding some detail here?