getAlby / lndhub.go

Accounting wrapper for the Lightning Network. It provides separate accounts for end-users. (LndHub compatible API written in Go)
GNU General Public License v3.0
87 stars 23 forks source link

Investigate 3rd party Authorization flows #180

Closed kiwiidb closed 2 years ago

kiwiidb commented 2 years ago

It should be possible to give an application or service access to your LNDhub account without giving up the full "admin" lndhub connection string. This kind of Authorization could have "create invoice" access, "read transactions" access or "make payment" access with monthly budgets. The Authorization should be time-scoped and a user should be able to have an overview of linked applications and be able to revoke access.

kiwiidb commented 2 years ago

An obvious candidate for this authorization flow would be OAuth2. LNDhub.go already uses JWT tokens for Authentication, which integrate well with , and this could be extended for 3rd party Authentication and Authorization. See this repository for a good overview of the protocol and a server implementation in Go. Parts of the examples in this answer come from there.

The problem with OAuth2 is that it is centralized in the sense that the client app needs to connect using a specific host (Github, Google, Facebook,...). In our case, many wallet providers would be possible and they may be self-hosted by the user. So to initiate the OAuth2 flow, it would be better to use a lightning or lnurl hyperlink which a user can use with both a mobile wallet or browser-based wallet (Alby). The redirect URL of the OAuth flow would then contain the host where the client app can go to generate an access token and make API calls. This host could be a hosted LNDhub, self-hosted LNDhub (even over Tor if the client app supports it), or a more exotic LNDhub implementation that works through mobile notifications to a mobile non-custodial wallet.

We decided it would be better to follow the normal OAuth flow and use a specific host to integrate as normal. Services could integrate multiple providers (eg. Alby) as they see fit, or they could allow a user to manually input the hostname of their self-hosted provider if they wish to do so.

So the flow could be roughly:

https://getalby.com/authorize?client_name=app_name&redirect_uri=https%3A%2F%2Fwww.example.com&response_type=code&state=somestate&scope=invoices:create%20budget:10000:monthly.

The possible scopes could be:

Multiple scopes can be seperated by a space (which should be URL-encoded ofcourse).

The pre-register step to obtain a client id and client secret would be optional, the choice is on the wallet provider if they require it or not.

curl --compressed -v https://getalby.com/v1/oauth/tokens \
    -u test_client_1:test_secret \
    -d "grant_type=authorization_code" \
    -d "code=7afb1c55-76e4-4c76-adb7-9d657cb47a27" \
    -d "redirect_uri=https://www.example.com"
{
  "user_id": "1",
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
  "expires_in": 3600,
  "token_type": "Bearer",
  "scope": "invoice:create budget:10000:monthly",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}

Inside LNDhub, a user would be able to view their linked applications, their permissions, their budgets. They could edit buttons and permissions, see what applications are doing and revoke access to applications.

This OAuth server could be implemented as a seperate service, or as a subsystem of lndhub.go. I am arguing in favour of the latter for the following reasons:

Creating a subdaemon inside lndhub that is used by echo to define a middleware on, has it's own database and controllers seems like the best option.

kiwiidb commented 2 years ago

What do you think about this @bumi ?

kiwiidb commented 2 years ago

@prusnak Do you mind to share your thoughts on my post above? We would like to get some more opinions on this topic :)

prusnak commented 2 years ago

I won't provide my own opinion on this topic as I don't consider myself a well experienced web developer. However, my gut feeling is that your direction in this area is good! 👍

kiwiidb commented 2 years ago

Follow-up issue: getAlby/oauth2server#1

prusnak commented 2 years ago

Does it make sense to allow account creation via the 3rd party auth flow? If so, how would that work?

kiwiidb commented 2 years ago

Doesn't really make sense I think since the purpose is to allow a 3rd party to access an existing user's account. The creation endpoint should be open to be called without authentication, unless it's been disabled, right?

kiwiidb commented 2 years ago

After a discussion with @bumi I've started to think how we could implement this entire service as a complete stand-alone service / API gateway using https://github.com/go-oauth2/oauth2.

OAUTH LNDHUB drawio(1)

This architecture would allow us to ship this feature without any changes whatsoever needed to the existing LNDhub codebase, moving everything to a seperate service (and some front-end client work).

bumi commented 2 years ago

I like the idea that we can implement this standalone and keep lndhub small and flexible.

If we implement a permission system (and for that we can use JWT or macaroons) in LNDHub then by default we would also not require an API gateway. (this could be optional)

The oAuth Server creates access tokens through an API endpoint in LNDHub (authenticated with some admin master user credentials). The 3rd party app then can use those credentials to do calls to LNDHub directly.

This way the initial authentication can be implemented independently of LNDHub and can also be part of another user-facing app (like for example getalby.com in our case)

image