boltwall icon indicating copy to clipboard operation
boltwall copied to clipboard

Seperate authorization to different routes

Open GeorgeTsagk opened this issue 3 years ago • 6 comments

Current implementation has a global perception of authorizing a client. E.g. After I pay the invoice I can provide the Authorization header and access a protected resource, but this same header will allow me to pass through any other protected route. There is no differentiation between which resources this specific header can access.

I have tried defining different boltwall middleware instances like this

app.get('/download', boltwall(options), fileController.downloadFile);

app.post('/upload', boltwall(options), fileController.uploadFile);

but it doesn't seem to get the job done as paying the /download endpoint will also grant me access to the /upload endpoint

Is there a way to provide access to specific routes and not to the whole API?

GeorgeTsagk avatar Jun 18 '21 14:06 GeorgeTsagk

Hey @GeorgeTsagk

Thanks for filing this issue and so sorry for the delay. Not sure why I never got an email from GitHub.

In any case, the most straightforward solution that comes to mind with the given setup would be to create a custom config that checks on a per path basis. A pre-built one comes with boltwall that is going to be similar to what you need, the ORIGIN_CAVEAT_CONFIGS which makes sure that an LSAT is only valid for the originally requesting origin IP. So in your case you would have one for each path, or create a function that takes a path and returns a new config based on that path. That would then get passed into the instantiation of boltwall in the options as you have above. To see what this config would look like take a look at this file. You'll notice in that one that the caveat minter actually gets access to the request object, so you could make this dynamic such the path is pulled from the request object and used to create the caveat that's added.

This seems like a very useful caveat config to have actually. If you end up doing something like this, let me know as I'd be happy to consider adding it to the built in configs available with the library. And if you have any questions about how the caveats work, don't hesitate to reach back out. I'll make sure GH is sending me emails form now on!

bucko13 avatar Jun 29 '21 20:06 bucko13

Hey @bucko13 , thanks for commenting back.

I will eventually implement this caveat, and I shall also comment again once that is done.

GeorgeTsagk avatar Jul 03 '21 13:07 GeorgeTsagk

Hey @bucko13, alluding to your comment above, the getCaveats field is a function. To my understanding, this allows us to instantiate one config per many requests. However, the 'minAmount' is defined as a 'string | number,' which fixes the price for each request.

I'm wondering if there's a way is to adjust the 'minAmount' based on the request, without instantiating a unique config for each possible request.

For example: /paywall?id=1 has minAmount = 5 /paywall?id=2 has minAmount = 10

brh28 avatar Jul 06 '21 21:07 brh28

So, minAmount doesn't really "fix" the price. Perhaps it's confusingly named, but it's basically just a fallback or a default in case there is no amount indicated in the request so that if there's no way to determine how much to make the invoice for, there's something to use as a default.

The idea in boltwall is that the client can actually be the one that says how much it wants to pay. This may seem counter-intuitive, but when you tie this to the caveats in the LSAT it can be quite powerful: the request indicates how much the client wants to pay, and the caveats can restrict access based on how much they decided. With the caveat you can create access restrictions based on how much the client offered to pay without having to determine a fixed amount. So for example, if you have a time-based system with access for 1 minute per 100 sats, if the client asks for an invoice to pay 1000, boltwall can create an LSAT caveat that expires in 10 minutes. This is essentially what the built-in time config does here.

If you wanted to create a system where the user or client didn't have to make any decisions about the amount, and you wanted this all to happen on the server, you could create a middleware that's before boltwall that sets the amount in the request body (or a query string) based on the route. Then that gets passed to boltwall which will create the invoice based on this value (that happens here).

So, that would look something like this:

app.use((req, res, next) => {
  if (req.query.id === 1) req.query.amount = 5
  else if (req.query.id === 2) req.query.amount = 10
  next()
})

app.use(boltwall())

The above is very rough and you might want to do different customizations for sub paths or something, but hopefully that helps give you an idea.

As you can see, this check doesn't actually have to interact with boltwall at all. If all you want to do is only allow access if an invoice of a certain amount is paid, then you don't actually need a special caveat; the LSAT will be valid if the invoice created was paid and invalid if it wasn't. If you wanted to tie other conditions on it, like time, then you can add that via the configs.

Hope that helps!

bucko13 avatar Jul 07 '21 04:07 bucko13

Thank you @bucko13! Definitely gives some good direction. I’ll play around with this today.

brh28 avatar Jul 07 '21 14:07 brh28

Opened a PR to address this feature: https://github.com/Tierion/boltwall/pull/28

aaroncj1 avatar Feb 13 '23 22:02 aaroncj1