Using Blockstack for (centralized) server-side authentication

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.

Technical question:

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.

App-mining question:

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’s stopping you from authenticating Blockstack on the frontend and then sending the result to the backend (with HTTPS, CORS, etc all enabled)? Or is having a frontend out of the question?

There is no “talking to a specific Blockstack ID;” there is only the authentication request which is returned with a Gaia Token and other information or with an error – that is all.

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.

Interested to know how other people see this?

2 Likes

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.

1 Like

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”.

Hi @djnicholson, sounds like you want to look at the Radiks project @hank is building - this is a way to cache data being stored via Gaia into a centralised mong db. hope this helps…

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:

2 Likes

I use the authentication through a nonce on gaia for OI Chat. Here is the server part:

OI Chat is taking part in the app mining program.

If you want to include any user with a DID then there is a proposal for did auth at:

1 Like

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.

1 Like

Suppose I have a backend server that must store some user data as it has its own proprietary database. I would want to maximize anonymity by storing some unique identifier that cannot be traced back to the users blockstack id. What is the best way for the server to know that it is taking requests from an authenticated id without actually knowing what that ID is? i.e. separate the centralized service so that it doesn’t know who its communicating with, but ensure others cannot make requests on behalf of the authenticated user.

The only two solutions i can think of is

  1. Generate uuid server side and send this back to client to ‘create account’. User must then return signed uuid jwt to the server to make authenticated requests.

  2. Have the client encrypt the name of their blockstack ID and pass it as a jwt to the server.

Which method would be considered best practice/is there a better way of doing this?

Best practice here is to organise things so the user data is not stored centrally.

It’d be decentralised via user’s gaia hub under their control. Some data - with the users consent - can be considered public and indexed somewhere like a lucene index to make e.g. marketplace functionality possible. Radiks is the main resource for collaboration between users but you can roll your own.

1 Like

I understand this would be best practice to completely decentralize but assuming this is not possible due to database constraints which would be preferred option?

Im trying to create custodial lightning wallets and the database cannot be moved to Gaia storage. Additionally these require 100% server uptime which is not possible with current dApp model as far as im aware

The majority of user info would be decentralized but the server would need to query the lightning node to find out what the balance of a user is, not necessarily who that user is.

My preferred option would be 1. where the user signs the uuid. This goes also in the same direction as self-issued openid providers