I’m doing some initial research for a new Blockstack app. The app will allow users to sign in with Blockstack and store data in their GAIA storage. However there will also be a scenario where a user can choose to share data with a centralized service.
Is there a suggested/approved way to authenticate a Blockstack user to a server in a trustless way? I do not want to submit any Blockstack auth token or key to the server. The server only needs proof that it is talking to a specific Blockstack ID, it does not need to act on behalf of that user in anyway.
I could build my own “protocol” to do this, e.g. the server could generate a nonce and ask the user to write it to their GAIA storage (publicly viewable) then the server could check that the GAIA URL exists and contains the correct nonce. I don’t want to roll my own protocol if something simpler exists already, though.
Would this kind of architecture prevent the app from receiving app-mining rewards. The app overall will still be genuinely decentralized and give the user control of their own data stored in GAIA. It will just have some scenarios where the user chooses to also share data with a centralized service.
What do you mean by “sending the result to the backend”. I deliberately do not want to send the token to the backend as this would allow the server to act on behalf of the user. My server just needs proof that the user has control of a specific Blockstack ID.
Hi - just curious about this and want to check my understanding…
Json web tokens perform both authentication and resource access. The blockstack auth token is a standard json web token (albeit using elliptic curve cryptography) that is generated by blockstack browser during authentication and can then legitimately be passed to resource server to access some resource.
In this latter case you’d send it to the resource server as a bearer token. The resource server would unpack it and validate its signature and then check the scopes to see if it has permission to access the resource.
Cors headers etc can be used to stop the request ever reaching the resource server e.g. to filter out unwanted traffic at a higher level.
This seems a reasonable thing to do to me in cases where no state is being stored on the resource server - e.g. an ethereum gateway resource server might provide reads of smart contract data to a blockstack user with permission to access the smart contract - this means you can avoid meta mask and perform permissioned reads on ethereum.
It may even be possible to set additional scopes in the auth token on the client to help the resource server decide whether to grant access.
I agree with @mikecohen.id – you are only sending the token, not other data/etc. that the user is not allowed to control, so what’s the problem here?
Unless your server is a security risk… in which case you would instead write something to the Gaia Hub, or sign a custom token with the app public/private key given to you from the JWT on the client-side.
Exactly. I’m saying that my users should be able to treat my server as a security risk and still feel secure using my decentralized app. For example: What if my app allowed a user to store all of their photos in GAIA storage and then selectively choose certain photos to share publicly through a centralized service that I run? I would want my users to know (e.g. after reviewing open source code) that my centralized service will only see photos they want it to see, but I still want the centralized service to be able to attribute a specific photo to a specific Blockstack user.
Yes, agree. My question is, does some best practice for this already exist. Or should I just “roll my own”.
I just wanted to clarify this point. If you pass the authResponse token to the server, the server can validate that the user does own the Blockstack ID, but the server cannot act on behalf of the user. This is because the appPrivateKey is encrypted using a “transit token” that is only stored on the client.
App.co is a centralized app, and it uses this model of server-side Blockstack auth to validate usernames, but it cannot actually do anything on behalf of the user.
Here is the app.co API code for server-side Blockstack auth:
Awesome. I was unaware of the transit token. Thanks for explaining that, Hank. Also the sample code you provided to validate the authresponse on the server and extract the username will be very useful.