npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@web3auth/sign-in-with-ethereum

v4.2.2

Published

The primary purpose of this document is to define how Ethereum accounts authenticate with off-chain services. By signing a standard message format parameterized by scope, session details, and a nonce.

Downloads

1,089

Readme

Sign In With Ethereum

The primary purpose of this document is to define how Ethereum accounts authenticate with off-chain services. By signing a standard message format parameterized by scope, session details, and a nonce.

While decentralized identity is not a novel concept, the most common implementations of blockchain-based credentials are either certificate-based or rely on centralized providers. We're proposing an alternative that doesn't require a trusted third party.

Specification

The specification for Sign In With Ethereum is based on https://eips.ethereum.org/EIPS/eip-4361 with the intention to make it compatible with https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-74.md

The message created follows the following structure :-

CACAO

header: Headers;

payload: Payload;

signature: Signature;

Payload

  /** RFC 4501 dns authority that is requesting the signing. */
  domain: string;

  /** Ethereum address performing the signing */
  address: string;

  /** Human-readable ASCII assertion that the user will sign, and it must not contain newline characters. */
  statement?: string;

  /** RFC 3986 URI referring to the resource that is the subject of the signing
   *  (as in the __subject__ of a claim). */
  uri: string;

  /** Current version of the message. */
  version: string;

  /** Chain ID to which the session is bound, and the network where
   * Contract Accounts must be resolved. */
  chainId?: number;

  /** Randomized token used to prevent replay attacks, at least 8 alphanumeric
   * characters. */
  nonce: string;

  /** ISO 8601 datetime string of the current time. */
  issuedAt: string;

  /** ISO 8601 datetime string that, if present, indicates when the signed
   * authentication message is no longer valid. */
  expirationTime?: string;

  /** ISO 8601 datetime string that, if present, indicates when the signed
   * authentication message will become valid. */
  notBefore?: string;

  /** System-specific identifier that may be used to uniquely refer to the
   * sign-in request. */
  requestId?: string;

  /** List of information or references to information the user wishes to have
   * resolved as part of authentication by the relying party. They are
   * expressed as RFC 3986 URIs separated by `\n- `. */
  resources?: Array<string>;

Signature

  t: string; // signature scheme

  m?: SignatureMeta; // signature related metadata (optional)

  s: string; // signature

A sample sign in message would look like :-

localhost:8080 wants you to sign in with your Ethereum account:
4Cw1koUQtqybLFem7uqhzMBznMPGARbFS4cjaYbM9RnR

Sign in with Ethereum to the app.

URI: http://localhost:8080
Version: 1
Chain ID: 1
Nonce: zNTPldYfb8ESmhPmL
Issued At: 2022-04-25T14:51:12.040Z

Screenshot here

Workflow

  1. The user connects the wallet to the website.
  2. From the frontend pass the domain, address, statement, uri, version, nonce, issuedAt, expirationTime, notBefore, requestId, resources (Array) to the SignInWithEthereumMessage constructor. There is additional regex validation in place as mentioned in the below sections
  3. Nonce is needed as a security mechanism from replay attacks and hence it is generated at the server side.
  4. The created message needs to be prepared in a wallet friendly format for which .prepareMessage() needs to be called
  5. The resultant has to be passed to signMessage method of window.ethereum.request
  6. This function would return the signedMessage

Regex rules

Each field specified in the Specification section needs to follow the following regex rules

DOMAIN = "(?<domain>([^?#]*)) wants you to sign in with your Ethereum account:";
const ADDRESS = "\\n(?<address>0x[a-zA-Z0-9]{40})\\n\\n";
STATEMENT = "((?<statement>[^\\n]+)\\n)?";
URI = "(([^:?#]+):)?(([^?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))";
URI_LINE = `\\nURI: (?<uri>${URI}?)`;
VERSION = "\\nVersion: (?<version>1)";
CHAIN_ID = "\\nChain ID: (?<chainId>[0-9]+)";
NONCE = "\\nNonce: (?<nonce>[a-zA-Z0-9]{8,})";
DATETIME = `([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[Tt]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(.[0-9]+)?(([Zz])|([+|-]([01][0-9]|2[0-3]):[0-5][0-9]))`;
ISSUED_AT = `\\nIssued At: (?<issuedAt>${DATETIME})`;
EXPIRATION_TIME = `(\\nExpiration Time: (?<expirationTime>${DATETIME}))?`;
NOT_BEFORE = `(\\nNot Before: (?<notBefore>${DATETIME}))?`;
REQUEST_ID = "(\\nRequest ID: (?<requestId>[-._~!$&'()*+,;=:@%a-zA-Z0-9]*))?";
RESOURCES = `(\\nResources:(?<resources>(\\n- ${URI}?)+))?`;

Verification flow

The verify function takes in the following params (as VerifyParams)

signature
publicKey
domain
nonce
time (optional)

There are certain checks in place such as invalid domain check,nonce binding check, expiry checks etc

import nacl from "tweetnacl";
.
.
nacl.sign.detached.verify(encodedMessage, base58.decode(signature), base58.decode(publicKey))

If this function returns a true value then it is a valid signature

User flow

Userflow

Disclaimer :

We haven't undergone a Formal Security Audit yet.