Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement signMessage method #1210

Closed

Conversation

gtsonevv
Copy link
Collaborator

@gtsonevv gtsonevv commented Nov 27, 2023

Pre-flight checklist

  • I have read the Contributing Guidelines on pull requests.
  • Commit messages follow the conventional commits spec
  • If this is a code change: I have written unit tests.
  • If this changes code in a published package: I have run pnpm changeset to create a changeset JSON document appropriate for this change.
  • If this is a new API or substantial change: the PR has an accompanying issue (closes #678) and the maintainers have approved on my working plan.

Motivation

Implement signMessage, that allows users to sign a message for a specific recipient using their NEAR account. It returns the SignedMessage based on the NEP413.

Test Plan

Added unit tests

Related issues/PRs

Issue #678

@gtsonevv gtsonevv requested a review from frol November 27, 2023 07:41
Copy link

changeset-bot bot commented Nov 27, 2023

🦋 Changeset detected

Latest commit: 661cc65

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@near-js/wallet-account Patch
near-api-js Patch
@near-js/cookbook Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gagdiez
Copy link
Contributor

gagdiez commented Nov 27, 2023

Before this patch the logic was:

  • if the user is planning to interact with a specific contract, we can create a function call key specifically for that contract (and maybe for particular methods), so we do not interrupt them to sign.
  • if the user is planning to use their wallet in general, there is no need to create a function call key, since anyways the user will have to be asked to sign a transaction.

After this patch, the logic is: during requestSignIn we always create a key.

The problem is that creating a key with no contractId will result in a Full Access Key being created:

Screenshot 2023-11-27 at 11 09 22

The issue mentioned (#678) is not an issue, but an UX decision. The right way to go is: login users through wallet selector, and then ask the user to sign a message using signMessage, which I think is now supported by most wallets.

}

const accessKey = KeyPair.fromRandom('ed25519');
Copy link
Contributor

@gagdiez gagdiez Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flow will create a full access key if no contractId is given

@vikinatora
Copy link
Collaborator

Hey, @frol @gagdiez Should the issue(#678) be closed in that case? @gtsonevv and I are working on a grant to maintain near-api-js. We believe that irrelevant issues should be closed. The issue has been open for a long time and we assumed it's relevant.

@frol
Copy link
Collaborator

frol commented Nov 27, 2023

@gagdiez Thank you for the quick and thorough feedback!

@vikinatora The issue predates the NEP-0413 signMessage. The issue has never been properly triaged, and what @gagdiez said is true, instead of leading users of near-api-js down the wrong path of creating a useless Full Access key, we should integrate signMessage to just "confirm that the Wallet is authenticated and thus will be usable for transaction signing when it will be necessary in the future":

The impact is that an app requesting NEAR account sign in must supply a contract in order to permit tx/message signing behavior, even if they have no need for contract functionality.

"signMessage" adoption and implementation in wallet-selector also got stuck: near/wallet-selector#883, and it would be awesome if you will be able to push it through the finish line.

In order to be productive, please, comment on the issues with some initial thoughts on the implementation you plan to execute and mention @gagdiez and myself, so we can help you to avoid going a false route.

@gagdiez
Copy link
Contributor

gagdiez commented Nov 30, 2023

@gtsonevv @frol please notice that signInMessage is just a particular instantiation of signMessage which now is implemented by most wallets.

Here is how the signMessage can be implemented, and remember that the key used to sign must always be a full access key: https://github.com/gagdiez/near-login/blob/3c0ad7d6587c835202b06d36afbde50ee6c6fec9/tests/authentication/wallet.ts

@gtsonevv gtsonevv requested a review from gagdiez December 6, 2023 11:28
@gtsonevv gtsonevv changed the title Fix requestSignIn function Implement signMessage method Dec 6, 2023
@gtsonevv
Copy link
Collaborator Author

gtsonevv commented Dec 6, 2023

Hey @frol @gagdiez, I think this PR is ready for review.

Copy link
Collaborator

@frol frol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I miss something, this is not the right direction.

I am not even sure if anything actually needs to be added in near-api-js at all. I am not familiar with the current relationship with wallet-selector, but as a developer who wants to add "login" that won't need to have a limited access key, I would integrate Wallet Selector and use signMessage there: https://github.com/search?q=repo%3Anear%2Fwallet-selector%20signMessage&type=code

@gagdiez Do you have more context here or can you invite someone else?

@kujtimprenkuSQA
Copy link

Hi, I am a member of the wallet-selector team.

Adding the signMessage in the Account class this way is not quite right in my opinion since the payload/message is meant to be signed with a full access key and looks like the signing part in this PR is done with a local access key.

Since it's not recommended to have a full access key present on the dApp it would make more sense to have a signMessage / requestSignMessage on the WalletConnection and this method/function would only handle the redirect logic something like it's done for my-near-wallet here this would be somewhat beneficial for dApps that don't use wallet-selector or avoid repeating code in wallet-selector for browser wallets.

@gagdiez what do you think?

@frol
Copy link
Collaborator

frol commented Dec 7, 2023

@gtsonevv So let me try to explain all the context regarding #678. Here is the original request:

The impact is that an app requesting NEAR account sign in must supply a contract in order to permit tx/message signing behavior, even if they have no need for contract functionality.

So the request was to authenticate a user - confirm that they have access to the account, and if there would be any requests that needs to be sent on behalf of the user (authorize) those will require another interaction with the wallet, the dApp won't be signing those requests. This is done this way to avoid dApps requesting Full Access keys for general operatons, thus minimize chances of leaking user's private key.

The flow was historically called "verifyOwner", but then it turned into a more generic "signMessage" standard:

  1. dApp would generate some random message (see more details below)
  2. dApp asks user to sign the message with the full access key that they possess (Wallet Selector implemented it as "signMessage" API and each individual Wallet should have implemented this support similarly to how adding a Function-call-only Access key "login" flow was implemented) - that requires user to interact with their wallet to confirm signing the request, but instead of signing a transaction, Wallets sign this random message and pass it back to dApp as a proof of access key possession
  3. dApp receives the signed message and verifies the signature and that the account id has the relevant access key registered on chain - this means that user has the private key and we can authenticate them

Regarding the "random message", it can be just Authenticate me, but maybe we need to add something else there. I don't recall other security threats that were considered there (replay attack is mitigated by using nonce).

@frol
Copy link
Collaborator

frol commented Dec 7, 2023

@kujtimprenkuSQA @gagdiez @andy-haynes That being said, I believe this "verifyOwner" belongs to wallet-selector library, and not near-api-js, which tries to be platform-agnostic and such features do not make sense for Node.js. Should we document how to use wallet-selector for the scenario reported in #678 and close this issue?

@kujtimprenkuSQA
Copy link

@kujtimprenkuSQA @gagdiez @andy-haynes That being said, I believe this "verifyOwner" belongs to wallet-selector library, and not near-api-js, which tries to be platform-agnostic and such features do not make sense for Node.js. Should we document how to use wallet-selector for the scenario reported in #678 and close this issue?

I agree that "verifyOwner" -> "signMessage" should belong to wallet-selector where the API is consistent for different wallets.

There's documentation for the "login" with signMessage in near docs:
https://docs.near.org/develop/integrate/backend-login

The signMessage API is documented in the wallet selector too:
https://github.com/near/wallet-selector/blob/main/packages/core/docs/api/wallet.md#signmessageparams

The original issue here was opened before the NEP-413 was approved.

Do we need more documentation than what currently is available?

@gagdiez
Copy link
Contributor

gagdiez commented Dec 7, 2023

I agree that this needs to be done by a wallet, since a fullAccessKey needs to be used, lets not add it to near-api-js and let wallet-selector handle it.

@gtsonevv gtsonevv closed this Jan 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

requestSignIn does not set localStorage key without contractId.
5 participants