How can the listener verify the identity of the dialer?

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)
      }
    })
}