decentralized-identity / did-jwt-vc

Create and verify W3C Verifiable Credentials and Presentations in JWT format

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fold alg into signer property of Issuer

oed opened this issue · comments

Reviewing this codebase. Really like the concept of an Issuer interface.

Right now it looks like Issuer has three properties did, signer, and alg?. Here alg seems a bit out of place. If this could somehow be folded into the signer property it would make the interface a lot cleaner.

Right now Signer is defined as:

type Signer = (data: string) => Promise<EcdsaSignature | string>

Could it be changed to something like this?

interface Signer {
  (data: string) => Promise<EcdsaSignature | string>;
  alg?: string;
}

The goal of the Issuer interface was to provide a common envelope for these 3 properties that need to match to be able to verify the resulting JWT through did-jwt.

did-jwt resolves the iss field to collect a list of public keys that should be valid signers of a JWT. The signature produced by the signer needs to match one of those keys as well as the algorithm of the header. If we are to change the interface it would introduce a new level of indirection without any real benefit.

BUT, this issue raises the question if the Issuer interface is even needed, or if it should be defined here.
It is essentially a subset of the properties of the JWTOptions interface used in did-jwt so it makes a bit more sense to define the Issuer interface in did-jwt and use it here, or even remove it completely and no longer create confusion.

I like the general idea of the Issuer interface, and I was intrigued by the fact that EthrDID actually implements it. Made me think that it could work as a general interface for interacting with DIDs. Maybe you would consider that out of scope though?
Totally makes sense for this to live in did-jwt.

and I was intrigued by the fact that EthrDID actually implements it

yeah, ethr-did is doing a "drive-by implementation" just because the types match 😅

What do you think of something like this (exposed by did-jwt):

export interface Issuer {
  did: string
  signer: (data: string) => Promise<string>
}

export interface JWTOptions extends Issuer {
  expiresIn?: number,
  header?: Partial<JWTHeader>
}

alg?: string is already a property of JWTHeader

and any method that generates JWTs would accept a JWTOptions parameter:

const token = createJWT(payload, {did, signer, header: {alg: 'ES256K'} })

ethr-did is doing a "drive-by implementation" just because the types match 😅
haha :)

As a developer I'd like to not have to care about the internal of some issuer that I'm using. For example:

const user1: Issuer = new EthrDID(...)

const user2: Issuer = new ThreeId(...)

const jwt1 = await createJWT(payload, user1)

const jwt2 = await createJWT(payload, user2)

Here EthrDID will use ES256K-R while 3ID uses ES256K. It seems like a leaky abstraction if I as a dev need to know this.

Right. I totally agree that basics could be simpler but ultimately it's a key that signs, not a DID.
A DID may express multiple keys in their DID doc.
Also, in the case of ES256K vs -R it's the same key that can produce both signatures so there should be a way to override that.

Right, but all of that can be handled from within the EthrDID, or ThreeId libraries.

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.