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

Adds the ability to add 'scopes' to a gaia auth token #545

Closed
wants to merge 6 commits into from

Conversation

hstove
Copy link
Contributor

@hstove hstove commented Sep 25, 2018

This implements the client-side requirements to work with our new 'scoped auth tokens' feature in Gaia.

Essentially, you can create an auth token with a scopes parameter in the payload. See stacks-network/gaia#142 (comment) for more info, and stacks-network/gaia#145 for the gaia PR.

Here is a code sample that I've tested in a local application, and it works as expected:

const userData = blockstack.loadUserData();
const hubUrl = 'http://localhost:4242'; // my local gaia hub
const { appPrivateKey } = userData;
const scopes = [
  {
    scope: 'putFilePrefix',
    domain: 'testingScoped',
  },
];
const gaiaConfig = await connectToGaiaHub(hubUrl, appPrivateKey, scopes);
try {
  await uploadToGaiaHub('shouldnt-work', 'asdf', gaiaConfig);
} catch (error) {
  console.log('Correctly failed to upload');
}
await uploadToGaiaHub('testingScoped/should-work', 'asdf', gaiaConfig);
console.log('Write was successful');

Overall I'm extremely excited about the possibilities this opens up for decentralized collaboration.

@CLAassistant
Copy link

CLAassistant commented Sep 25, 2018

CLA assistant check
All committers have signed the CLA.

@hstove hstove changed the base branch from master to develop October 24, 2018 16:04
@hstove
Copy link
Contributor Author

hstove commented Oct 24, 2018

Rebased from develop so that maybe one day we can merge 😄

@kantai
Copy link
Collaborator

kantai commented Oct 26, 2018

Hey @hstove! I'll try to wrap a review on this in the next couple days

Copy link
Collaborator

@kantai kantai left a comment

Choose a reason for hiding this comment

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

This looks great @hstove -- two things I would suggest, though:

  1. It'd be great to have unit test coverage for the scopes field. Something like just testing its presence in the outputted JWT from connectToGaiaHub() is probably enough.

  2. We should have JSDocs for the connectToGaiaHub function -- it now has enough additional features over just using the Blockstack session's automatic connection that developers may want to be calling it directly.

@hstove hstove self-assigned this Oct 30, 2018
@kantai
Copy link
Collaborator

kantai commented Nov 5, 2018

Awesome, thanks for the updates @hstove -- this looks good to me

@moxiegirl
Copy link

JeHunter commented:

Very excited about this one. When it’s merged, will the core blockstack.js documentation be updated to support scoped auth tokens. I looked at Hank’s example in the PR and it wasn’t entirely clear to me how to set the scopes and enforce them.

@hstove
Copy link
Contributor Author

hstove commented Nov 16, 2018

Yes, we'll definitely update our docs. I can write up some of that stuff.

I'm not sure how we want to move forward with this. @kantai has reviewed an approved. @larrysalibra or @yknl any thoughts or should we move forward? Are we waiting on anything for the user session PR?

* @param {string} gaiaHubUrl - the Gaia hub URL you want to connect to
* @param {string} challengeSignerHex - a private key used for signing an auth token
* @param {string} associationToken - an optional association token to add to your auth token
* @param {string} scopes - an optional array of scopes to include which will only allow
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could include better documentation on the scopes array here -- basically saying what the scopes array can be used for. What do you think about including that documentation here versus in the gaia docs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it'd be best to have them in both places. I'll add more specific notes to the blockstack.js docs here - good idea.

@kantai
Copy link
Collaborator

kantai commented Nov 16, 2018

Hmm -- @hstove, it might make sense to include docs on what the scopes array is used for in blockstack.js rather than in gaia -- what do you think about those two options?

@friedger
Copy link
Collaborator

While this is really nice, it does not (yet?) affect the public API.

Will the scope be introduced to the UserSession creation? That gives developers the assurance that the app only writes to the right domain/file path.

Are the other motivations for this? Could you add them to the PR?

Copy link
Contributor

@larrysalibra larrysalibra left a comment

Choose a reason for hiding this comment

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

I've read through the original github issue thread in the gaia repo and have trouble seeing a use case of this that can't also be solved with gaia inboxes and do so without giving a 3rd party relatively unfettered (beyond a file name/path prefix) write access to your app's storage bucket.

@markmhx asked a similar question and the response he got from @aulneau and @hstove was "we need this for team apps"

Can you expand on this?

Is the idea that in a team app, there would be one owner and all the data would be written in the owner's storage bucket?


@friedger writes

While this is really nice, it does not (yet?) affect the public API.

Will the scope be introduced to the UserSession creation? That gives developers the assurance that the app only writes to the right domain/file path.

To build on @friedger 's comments:

It seems like this functionality for uploading a file using a scoped auth token should be added to the putFile method instead of pulling in lower-level, non-public (in this library) implementation methods.

Let me walk through what I understand as a typical use case for this feature.

Assume an app example.com with two users Alice and Bob. Alice wants to let Bob upload files to her gaia hub in her example.com storage bucket under the path prefix bobs-stuff/.

  1. Alice's instance of example.com generates a scoped gaia auth token with the following data:
const scopes = [
  {
    scope: 'putFilePrefix',
    domain: 'bobs-stuff/',
  },
];
  1. Alice's instance of the app sends the generated scoped gaia auth token to bob in a secure manner (ie. by encrypting it for bob and storing it in in a known location in alice's gaia storage bucket).

  2. Bob's instance of the app uses the scoped gaia auth token to write bobs-stuff to Alice's by providing the scoped gaia auth token to the putFile function.

We're currently missing a developer-friendly API for generating the auth token in step 2 and a way for communicating it to user in another app instance.

Here's how a more developer friendly api might look:

// alice's app instance

import { UserSession } from 'blockstack'

// assume alice has already signed in

const userSession = new UserSession()

userSession.createStorageToken({username: 'bob.id', path: 'bobs-stuff/')
// bob's app instance

import { UserSession } from 'blockstack'

// assume bob has already signed in

const userSession = new UserSession()
const options = {  bucket: { username: 'alice.id' }}
const content = { 'stuff': 123 }
userSession.putFile('/bobs-stuff/item.json', content, options)

/** 

The above options object implies:
const options = { encrypt: true, encryptToUser: 'alice.id', bucket: {username: 'alice.id', appDomain: 'https://example.com'}, sign: true } 
*/

This example adds an additional option bucket to putFile to specify in which storage bucket the file should be written.

It also adds a function createStorageToken that generates the scoped gaia storage token, encrypts it for the given user and stores it a known location.

Specifying a bucket in putFile retrieves the scoped storage token in the known location, decrypts it and then attempts to write the file content to that location.

The above pseudo code assumes the ability to look up a key for another user ships first: #458

Please let me know if i've misunderstood the use case of this feature. Happy to discuss in more detail.

@jcnelson
Copy link
Collaborator

Is the idea that in a team app, there would be one owner and all the data would be written in the owner's storage bucket?

Yes -- if Alice does not have a Gaia hub at all, Bob can share his storage with her using this feature.

Is the idea that in a team app, there would be one owner and all the data would be written in the owner's storage bucket?

Yes -- in corporate/enterprise settings, it may be the case that employees do not have Gaia hubs at all, but instead share one operated by their department (for example). In this case, the department manager is the data owner.

We're currently missing a developer-friendly API for generating the auth token in step 2 and a way for communicating it to user in another app instance.

I consider this to be a feature. We want the easiest way of using Gaia to be assuming the user has their own Gaia hub; we don't want to encourage developers to build apps where most users don't own their own data. But, that said, I think your recommended API changes (e.g. createStorageToken()) are reasonable.

@kantai
Copy link
Collaborator

kantai commented Jan 17, 2019

Something I think we should add here is the ability to pass a Gaia config object into putFile --- that way someone wouldn't need to use uploadToGaiaHub, which doesn't do things like handle encryption or signing.

@hstove
Copy link
Contributor Author

hstove commented Jan 17, 2019

Something I think we should add here is the ability to pass a Gaia config object into putFile --- that way someone wouldn't need to use uploadToGaiaHub, which doesn't do things like handle encryption or signing.

Sure, but when you think about the use case, if you want to do signing or especially encryption with a scoped token, you're probably going to encrypt with a custom group key. Meaning we'd need to change putFile to support that, and signing too.

@kantai
Copy link
Collaborator

kantai commented Jan 17, 2019

Sure, but when you think about the use case, if you want to do signing or especially encryption with a scoped token, you're probably going to encrypt with a custom group key. Meaning we'd need to change putFile to support that, and signing too.

It sort of already supports both -- if you set encrypt or sign to a private key string, it uses the provided private key.

@hstove
Copy link
Contributor Author

hstove commented Jan 17, 2019

It sort of already supports both -- if you set encrypt or sign to a private key string, it uses the provided private key.

Ah, I actually didn't know that. Nice!

@zone117x zone117x assigned zone117x and unassigned zone117x Mar 19, 2019
@yknl
Copy link
Contributor

yknl commented Apr 23, 2019

@hstove is still working on this PR

@stackatron stackatron modified the milestones: DX Q3 1, DX Q3 Sprint 1 Aug 7, 2019
@hstove hstove removed their assignment Nov 11, 2019
@agraebe
Copy link
Contributor

agraebe commented Jan 26, 2021

closing this for now. please re-open if you think this requires attention. if you re-open, please also suggest who could help resolve and carry it to the finish line 🙏🏼

@agraebe agraebe closed this Jan 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet