w3t
TypeScript icon, indicating that this package has built-in type declarations

0.0.6 • Public • Published

Web3 Token

Development

Build: npm run build

Test: npm run test

Usage

Install

npm i w3t

Client

import {Web3Token} from "w3t";
import * as web3 from "web3";

//Mock the user in the crypto wallet. Use your web3provider install it.
const accounts = web3.eth.accounts.create();

// All users have the same msgMetadata
const msgMetadata = {
    domain: "example.com",
    statement: "Please Sign the Message.",
    uri: "https://example.com",
  // version: "1",
  // chainId: 1
}

const w3tokenClient = new Web3Token(msgMetadata);

// Each user have different msgPayload
const msgPayload = {
    address: accounts.address, // mock the user
    // nonce, issuedAt, expirationTime
}
const message = w3tokenClient.prepareMessage(msgPayload, {expiresIn:'12h'});

//Invoke the wallet and sign the `message`
const signature = web3.eth.accounts.sign(message, accounts.privateKey);

const token = w3tokenClient.create(signature.signature);

//Set the token in request headers and request the server
//... headers:{'Authorization': `Bear ${token}`}

Server

import {Web3Token} from "w3t";

//Get the token from the request headers
const token = req.headers.authorization.split(' ')[1]

//The server has the same msgMetadata
const msgMetadata = {
    domain: "example.com",
    statement: "Please Sign the Message.",
    uri: "https://example.com",
  // version: "1",
  // chainId: 1
}

const w3tokenServer = new Web3Token(msgMetadata);

try{
    const decoded_token = await w3tokenServer.verify(token, {maxAge:'3d'});
    const addr = decoded_token.payload.address;
    //...
}catch(e){
    //verify failed
    //...
}

Compatible With JSON Web Token

Server

import jwt from 'jsonwebtoken';
const token = req.headers.authorization.split(' ')[1];
const decoded_token =  jwt.decode(token);

if (decoded_token.header.typ === 'w3t'){
    // Web3 Token
} else if (decoded_token.header.typ ==='jwt'){
    // JSON Web Token
} else{
    // Invalid token
}

Message

Web3Token uses the EIP-4361 format message, which can avoid Blind Message Attack.

Some fields of EIP-4361 are still in dispute, such as chainId. However, in order to be compatible with EIP-4361, Web3Token still retains these fields.

Web3Token divides the message into two parts: msgMetadata and msgPayload.

On a website, fields such as domain and statement are the same in different messages. We extract these static fields as msgMetadata and omit these fields in web3token. Variable fields such as address in each message constitute msgPayload.

The client and server have the same msgMetadata, which is loaded during the web3Token initialization. The preparemessage() and verify() will automatically load msgMetadata when executed.

API

Web3Token Header

{alg: "ECDSA", typ: "w3t"}

MsgMetadata : Object

Name EIP4361 Required Web3Token Required Example
domain required required example.com
statement optional optional Please sign this message.
uri required required https://example.com/login
version required optional (default) default: 1 (MUST be 1)
chainId required optional (default) default: 1

MsgPayload : Object

Name EIP4361 Required Web3Token Required Example
address required required 0x12345...
nonce required optional (default) f040lq6s, default: siwe.generateNonce()
issued-at required optional (default) 2021-09-30T16:25:24Z, default: now()
expiration-time optional optional (default) 2021-09-30T22:25:24Z, default: now()+6h
not-before optional optional 2021-09-30T16:25:24Z
request-id optional optional 1
resources optional optional https://example.com/my-web2-claim.json
  • nonce: The Web3Token does not required a nonce, but the EIP4361 required, so this implementation just retains the field.

  • expiration-time: EIP4361 does not required the expiration-time, but Web3Token required because expiration-time can resist Replay Attacks.

  • nonce, issued-at and expiration-time have default values.

constructor(msgMetadata, options)

Name Required Description Example
msgMetadata required The static fields in messages, see Table MsgMetadata. { domain: 'example.com', statement: 'Please sign this message.', uri: 'localhost', version: 1, chainId: 1,}
options optional default: {maxAge:7d, expiresIn:6h}
options.maxAge optional Server Only: the longest valid duration of the client-issued token. {maxAge:7d}, See ms.
options.expiresIn optional Client Only: the valid duration of the token. expiresIn MUST <= maxAge {expiresIn:1d} See ms.

prepareMessage(msgPayload, expiresIn)

Name Required Description Example
msgPayload required See Table MsgPayload {address:0x12345... }
options optional default: {expiresIn:6h}
options.expiresIn optional expiration-time = issued-at + expiresIn 1d, default: 6h

Returns:

Type Description Example
string the message example.com wants you to sign in with your Ethereum account:0x123456789...

create(signature)

Name Required Description Example
signature required the user signed the message of prepareMessage() '0x98765...

Returns:

Type Description Example
string the token value aaaa.bbbb.cccc

verify(token, maxAge)

Name Required Description Example
token required See Table MsgPayload {address:0x12345... } or eyJzaWduYXR1cmUiOiI...
options optional default: {maxAge:7d}
options.maxAge optional maxAge >= issued-at - expiration-time 3d, default: 7d

Returns:

Type Description Example
object the decoded token {header:{alg: "ECDSA", typ: "web3token"},payload:{...MsgPayload},signature:'0x98765...'}

Security Consideration

  • Blind Message Attacks

EIP-4361

  • HTTPS

  • Replay Attacks

Package Sidebar

Install

npm i w3t

Weekly Downloads

1

Version

0.0.6

License

MIT

Unpacked Size

33.3 kB

Total Files

17

Last publish

Collaborators

  • doscool