regen-network / rnd-dev-team

RND Dev Team issue management (DEPRECATED)
0 stars 0 forks source link

Login with Keplr - Architecture Design #859

Closed S4mmyb closed 2 years ago

S4mmyb commented 2 years ago

Is your feature request related to a problem? Please describe. Currently, we have a regular authentication system that uses Auth0. We would like to build another one that would be based on Keplr login.

Describe the solution you'd like As a credit issuer or project page editor (which is currently a credit issuer), I want to be able to login with my Keplr account and have native permissions to make changes (see more detailed description in https://github.com/regen-network/regen-registry/issues/757#issuecomment-1062209517).

The user flow for logging in should be similar to the one on http://commonwealth.im/ The user can login with Keplr, signs a fake transaction (that won't be broadcasted, it's just a way of authenticating through a signature). A regular user is then created in the db, which has certain permissions to edit off-chain data. In our use case, the primary off-chain data that would need to be accessed would be project metadata stored in the postgres database.

This issue is about defining the back-end architecture for handling this use case and building an authentication system based on Keplr login. This could result in some written documentation and optionally some diagrams.

Commonwealth uses http://www.passportjs.org/ under the hood for authentication. We could use the same or start thinking about a more long term solution that would be based on building some Regen identity provider instead (though it might require a lot more work).

Additional context (optional)

For Admin Use

blushi commented 2 years ago

Hey team! Please add your planning poker estimate with ZenHub @wgwz @mhagel

wgwz commented 2 years ago

Suppose that one day I signed in via Keplr, and the next day I went via auth0 for some reason, would the desired result be that we have logic on the back-end to make sure that I don't end up with two different accounts in the user table?

blushi commented 2 years ago

I think we want those to be exclusive, either Keplr or Auth0 for now.

wgwz commented 2 years ago

One question I have is that when I sign in to commonwealth with Keplr, I can only sign in with my osmosis address: image.png

And I'm not seeing the option to sign in with my regen address (regen1rn2mn8p0j3kqgglf7kpn8eshymgy5sm8w4wmj4). So the question is, we want the users to be signing in with their regen address, right? Or does it not matter somehow?

I'm just assuming that we would need the regen address because of this comment from Cory but again maybe I'm just missing a technicality:

The app detects that a user’s regen account is issuer who created this on-chain project, and therefore exposes an exposes an “edit” button on the project page so the user can add profile pictures and other fully-offchain/centralized metadata The user can edit & save metadata, as well as add other regen user account names as “collaborators” so they can directly edit project page website as well

wgwz commented 2 years ago

I think we want those to be exclusive, either Keplr or Auth0 for now.

@blushi so just to confirm, does this mean we will only have one and not the other? or does it mean that we have both, and we are ok with the user accounts being separate? i think i'm caught up in semantics

blushi commented 2 years ago

@blushi so just to confirm, does this mean we will only have one and not the other? or does it mean that we have both, and we are ok with the user accounts being separate? i think i'm caught up in semantics

Users can log in with either one or the other, both options are available, but if you first log in with Keplr, log out and then log in with Auth0 then this would result in 2 different users.

blushi commented 2 years ago

One question I have is that when I sign in to commonwealth with Keplr, I can only sign in with my osmosis address:

you need to go to https://commonwealth.im/regen in our use case, we only want regen addresses

wgwz commented 2 years ago

Do we have any architecture design templates or previously documented architectures (within notion or elsewhere) that I could look at to see what the output documentation for this task could be like? Thanks!

blushi commented 2 years ago

We don't predefined templates yet for this kind of docs (maybe we should think about it!) but I can think of these docs on Notion:

or the ADRs on cosmos-sdk: https://github.com/cosmos/cosmos-sdk/tree/master/docs/architecture that we could take some inspiration from.

wgwz commented 2 years ago

These are just some loose notes as I'm tracing through the way that the auth system currently works. Please feel free to point out where I'm missing info. Questions are highlighted with an underline, everything else is just me thinking out loud.

  1. I believe this is the highest-level orchestration of things in the regen-web side. It seems to be where WalletProvider, AuthApolloProvider and Auth0Provider are instantiated (?? not sure if that's the right term for what's happening here).

Question: I wonder at which level would it be best to make modifications for the Keplr login. Would we need to create a new level there called AuthKeplrProvider?

  1. It seems like AuthApolloProvider is specific to auth0 authentication through this dependency. So I would guess that we probably do want to have a separate provider (in relation to question above).

  2. The AuthApolloProvider is connected to the registry-server via this request. This request sends the user object from auth0.

  3. The registry server in turn makes use of the auth0 user object. The first thing that happens is we get the users auth0 user id from the sub claim. If it didn't already exist we grant the app_user role to that user's newly created user role (via here and then here). The second thing that happens is we actually add this user to our database and via here and here.

So the sub represents a unique user id on auth0. This value ends up in the user table under the auth0_sub. So each user also has a unique role corresponding to their sub. (Side-note: For a list of roles select * from pg_roles, for the list of policies select tablename, policyname, roles from pg_policies.)

At this point in time, in doesn't seem like we have a one-to-many relationship between the user and wallet table. I think this could matter in edge-cases where maybe a user has multiple wallets which are connected to different projects (Is it possible?). In order to manage the data for one project they might have to sign-in to one Keplr wallet, and then sign-out and sign back in with a different account (somewhat inconvenient).

Question: Should we be assuming for now that each user has only one regen address?

Question: Can we talk through this relationship in the DB and how it maps to our domain? user => party => wallet. I.e. what is the concept of the party, and why are those attached to wallets? Does each user get modeled as it's own party or is a party a group of users (with shared access to a wallet)?

Next steps:

blushi commented 2 years ago

Question: I wonder at which level would it be best to make modifications for the Keplr login. Would we need to create a new level there called AuthKeplrProvider?

Probably but this isn't really the purpose of this issue which should be focused on back-end.

So the sub represents a unique user id on auth0. This value ends up in the user table under the auth0_sub. So each user also has a unique role corresponding to their sub. (Side-note: For a list of roles select * from pg_roles, for the list of policies select tablename, policyname, roles from pg_policies.)

Indeed.

At this point in time, in doesn't seem like we have a one-to-many relationship between the user and wallet table. I think this could matter in edge-cases where maybe a user has multiple wallets which are connected to different projects (Is it possible?). In order to manage the data for one project they might have to sign-in to one Keplr wallet, and then sign-out and sign back in with a different account (somewhat inconvenient).

Question: Should we be assuming for now that each user has only one regen address?

That's a good question, I believe we should add the ability for one single user to manage multiple wallet addresses (just like it's the case on keplr or commonwealth, see screenshot), any thoughts on this? cc/ @erikalogie @S4mmyb @clevinson

image

Question: Can we talk through this relationship in the DB and how it maps to our domain? user => party => wallet. I.e. what is the concept of the party, and why are those attached to wallets? Does each user get modeled as it's own party or is a party a group of users (with shared access to a wallet)?

We have a party table to represent one individual user or one organization (1 user <=> 1 party or 1 org <=> 1 party). We added this party table so that we can reference it in the project table in particular, for all the project stakeholders references (ie in the developer_id) because those project stakeholders could be either individual persons or organizations.

My thought is that the auth0 user id sub can be replaced with a regen address, since this is an equivalent that uniquely identifies the user.

Not necessarily if we want to support one user account to be mapped to multiple wallet addresses.

The thing I cannot see, is if we would need to make changes to policies in the DB. This is a piece to understand better.

Most policies rely on get_current_user_id function, which is based on the auth0_sub, so we might need to adapt it.

erikalogie commented 2 years ago

I don't think we'd support adding multiple regen addresses in the UI at first, but I suppose we might want to do that in the future so it makes sense to plan for it.

This might help @wgwz with visualizing how we'd be potentially allow for editing of org/individual profiles related to a singular regen address in the future in the UI: https://www.figma.com/file/B85IQijD2Ul7sVzVWqXmQW/Crypto-Happy-Path?node-id=192%3A40725

wgwz commented 2 years ago

We have a party table to represent one individual user or one organization (1 user <=> 1 party or 1 org <=> 1 party). We added this party table so that we can reference it in the project table in particular, for all the project stakeholders references (ie in the developer_id) because those project stakeholders could be either individual persons or organizations.

I see, so if we wanted to get all the project stakeholders for a particular project, in SQL we would do something like this:

select
    handle as "project.handle",
    party.id as "party.id",
    party.name as "party.name"
from
    project,
    party
where
    project.developer_id = party.id
    and handle = 'wilmot'
;
project.handle party.id party.name party.type
wilmot 02f34b6e-8304-11ea-b9f6-0267c2be097b Impact Ag Partners organization

In this case we have a single organization as the project stakeholder. But it is also possible for party.type to be a user.

wgwz commented 2 years ago

Just some more notes as I'm looking at how our system currently works from a back-end perspective. I'm also writing with an eye towards how multiple wallets for a single user, or an organization could be achieved. TL;DR I think our current data model on the back-end can accommodate it as is (which is pretty cool).

This visual representation has been helpful for me thinking through this stuff (see here for how to read the relationship arrows). At present I've focused mostly on the user, party and wallet portion of the diagram.

It looks like every user is always associated to their own party via this part of the user creation process. However not every user adds a wallet during the user creation process (it's an optional value at present). If the users wallet was present is does become linked to that users "party". That means we can look up a users wallet(s) as something like:

select
    "user".id as "user.id",
    "user".email as "user.email",
    "wallet".addr as "wallet.addr",
    "party".type as "party.type"
from
     "user"
join
    "party"
on
    "user".party_id = party.id
join
    "wallet"
on
    "party".wallet_id = "wallet".id
where
    "party".type = 'user'
    and "user".id = '58e7aec6-6557-11eb-8c65-0267c2be097b'
;
user.id user.email wallet.addr party.type
58e7aec6-6557-11eb-8c65-0267c2be097b example@gmail.com \x6578616d706c65 user

Another thing to note is that because we have a unique party corresponding one-to-one with a given user, and the party table has a one-to-many relationship with the wallets table, in theory we add more than one wallet for a given user through that linkage. I believe the same things are true for the organization to party to wallet relationship.

blushi commented 2 years ago

We have a party table to represent one individual user or one organization (1 user <=> 1 party or 1 org <=> 1 party). We added this party table so that we can reference it in the project table in particular, for all the project stakeholders references (ie in the developer_id) because those project stakeholders could be either individual persons or organizations.

I see, so if we wanted to get all the project stakeholders for a particular project, in SQL we would do something like this:

select
  handle as "project.handle",
  party.id as "party.id",
  party.name as "party.name"
from
  project,
  party
where
  project.developer_id = party.id
  and handle = 'wilmot'
;

project.handle party.id party.name party.type wilmot 02f34b6e-8304-11ea-b9f6-0267c2be097b Impact Ag Partners organization In this case we have a single organization as the project stakeholder. But it is also possible for party.type to be a user.

In this case, it's only selecting the project developer (other project stakeholders are land steward, land owner, etc.). It's possible for party.type to be a user indeed, that's the whole point of having this party table.

blushi commented 2 years ago

Just some more notes as I'm looking at how our system currently works from a back-end perspective. I'm also writing with an eye towards how multiple wallets for a single user, or an organization could be achieved. TL;DR I think our current data model on the back-end can accommodate it as is (which is pretty cool).

This visual representation has been helpful for me thinking through this stuff (see here for how to read the relationship arrows). At present I've focused mostly on the user, party and wallet portion of the diagram.

It looks like every user is always associated to their own party via this part of the user creation process. However not every user adds a wallet during the user creation process (it's an optional value at present). If the users wallet was present is does become linked to that users "party". That means we can look up a users wallet(s) as something like:

select
    "user".id as "user.id",
    "user".email as "user.email",
    "wallet".addr as "wallet.addr",
    "party".type as "party.type"
from
     "user"
join
    "party"
on
    "user".party_id = party.id
join
    "wallet"
on
    "party".wallet_id = "wallet".id
where
    "party".type = 'user'
    and "user".id = '58e7aec6-6557-11eb-8c65-0267c2be097b'
;

user.id user.email wallet.addr party.type 58e7aec6-6557-11eb-8c65-0267c2be097b example@gmail.com \x6578616d706c65 user Another thing to note is that because we have a unique party corresponding one-to-one with a given user, and the party table has a one-to-many relationship with the wallets table, in theory we add more than one wallet for a given user through that linkage. I believe the same things are true for the organization to party to wallet relationship.

Well right now, it's the other way around. One wallet can be associated with multiple parties. Indeed, we have only one wallet_id reference in the party table. If we want to support multiple wallets per party in the future then we might need to change that.

wgwz commented 2 years ago

Well right now, it's the other way around. One wallet can be associated with multiple parties. Indeed, we have only one wallet_id reference in the party table. If we want to support multiple wallets per party in the future then we might need to change that.

Ah ok, of course, my mistake, thanks for clarifying that. Somehow I thought there was foreign key in the wallet table for party ID. Which clearly there isn’t.

So I suppose if we were to support one party having multiple wallets we would need to add an association table between party and wallet (to support what would be a many-to-many relationship there)

wgwz commented 2 years ago

In this case, it's only selecting the project developer (other project stakeholders are land steward, land owner, etc.). It's possible for party.type to be a user indeed, that's the whole point of having this party table.

I think I was working under a similar faulty assumption here. I misunderstood the relationship. I.e Each project developer can have multiple projects. But a project does not have multiple project developers.

Please bear with me, if I’m just stating glaringly obvious facts as I’m working through this 😅

wgwz commented 2 years ago

I just wanted to write up some thoughts from our brief convo yesterday @blushi, please add any other thoughts you have or things that I might be missing or forgetting!

TL;DR I think our current data model on the back-end can accommodate it as is (which is pretty cool).

This conclusion was not correct, because of the fact that while each user has their own unique party association, the relationship between the party and wallet table, at present, defines a relationship that one wallet can have many party's. If we want to follow this path for associating multiple wallets to a single user then we need to change that relationship to go in the other direction.

I'm going to switch gears though. I'm now going to focus on the process for a user with a single-wallet. Including importantly the verification/validation step that needs to happen on the back-end each time a user logs in. Also important here is figuring out how we will make use of JWT or something like it to provide a user session in the front-end.

S4mmyb commented 2 years ago

@wgwz will split into multiple tasks for the 3/29 sprint.