How can the listener verify the identity of the dialer?

Hi, I would like to know how can I verify the identity of the sender of a message via a stream ?
I’m currently working with a private network with a swarmKey.

Seems like you want the same thing as me in the previous topic: Certificates/JWT-based authorization middleware in js-libp2p.

But if you need to identify a single stream then you can use it-handshake package, which is using in SECIO module and help to exchange some information between client and server to negotiate and acknowledge each other before passing the stream to the handling stream.

Server:

import handshake from 'it-handshake'
import pipe from 'it-pipe'

const ACCESS_TOKEN = "09AF..."

// Some boiler plate code ...
node.handle('/protocol/1.0', ({stream}) => {
  handleStream(stream)
  .catch(error => logger.error(error))
})

async function handleStream(stream) {
  const hs = handshake(stream)

  // Here goes your authorization logic
  const accessToken  = await hs.read()
  if (accessToken.toString() !== ACCESS_TOKEN) {
    hs.write("ACCESS DENIED")
    stream.close()
    return
  }
  
  hs.write("OK")
  // End handshake
  hs.rest()

  // Here goes your stream logic
  await pipe(
    ["Hello"],
    hs.stream,
    async function (source) {
      for await (const msg from source) {
         console.log('%s', msg)
      }
    })
}

Client:

import handshake from 'it-handshake'
import pipe from 'it-pipe'

const ACCESS_TOKEN = "09AF..."

// Some boiler plate code ...
const conn = node.dialProtocol(peerInfo, "/protocol/1.0")

handleStream(conn.stream)
.catch(error => console.error(error))

async function handleStream(stream) {
  const hs = handshake(stream)

  // Here goes your authorization logic
  hs.write(ACCESS_TOKEN)
  const result  = await hs.read()
  if (result.toString() !== "OK") {
    stream.close()
    throw new Error("Access denied")
  }
 
  // End handshake
  hs.rest()

  // Here goes your stream logic
  await pipe(
    [],
    hs.stream,
    async function (source) {
      for await (const msg from source) {
         console.log('%s', msg)
      }
    })
}

Thanks for your answer, I don’t know if in my case an auth token is what I need.
Actually, when a node received a message from a protocol. I want this node to know who send the message and I want that node to verify the signature of the sender.

Exemple :
I have a network with multiples nodes (Alice Bob Hector…)
QmAlice (PublicKeyAlice / PrivateKeyAlice) send a message to QmBob with protocol /chat.

How can QmBob know that QmAlice send him this message ?
–> Should I manually send in the message the dialer informations (QmAlice PublicKeyAlice and AliceSignature) ?

You should be able to check the remotePeer value on the connection. During the crypto exchange identities will be verified.

node.handle('/chat', ({ connection, stream }) => {
  console.log(connection.remotePeer) // The PeerId of the node we are connected to

  // Any messages sent over `stream` are verified to be from `remotePeer`
})

You don’t need to sign messages when streaming directly from that peer since the data was already encrypted by them.

1 Like

I’d suggest you not to use encryption keys for authorization. One user can have several devices and the encryption private key (as any other private key) shouldn’t leave the device it’s stored in. So you need to use DID to sign encryption key public key with users private key and then pass signed DID payload with the connection. Thus one user could connect to your service through different locations, and even with different transports, etc.

Thanks, it was what I was looking for. :slight_smile:

Thanks for your advice. I just didn’t understand the acronym DID. Could you me please enlight me ?

DID is a Decentralised Identifier. It’s something like certificate in SSL. JWT (JSON Web Token) also is suitable for this for authorisation.

1 Like