Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can NOT verify did:ether JWT token #22

Closed
maitien2004 opened this issue Oct 20, 2018 · 30 comments
Closed

Can NOT verify did:ether JWT token #22

maitien2004 opened this issue Oct 20, 2018 · 30 comments
Labels
bug Something isn't working

Comments

@maitien2004
Copy link

maitien2004 commented Oct 20, 2018

I try to use Ether-DID library to create new jwt token and after that i can NOT verify it.
Here is example code i used.

`const EthrDID = require('ethr-did');
const ethrDid = new EthrDID({
provider: web3.currentProvider,
address: 'address',
privateKey: 'priv-key'
});

var jwt = await ethrDid.signJWT({ claims: { name: 'Joe Lubin' } });
//Problem here
const { payload, issuer } = ethrDid.verifyJWT(jwt);
console.log(payload); // return undefined
console.log(issuer); // return undefined`

@froid1911
Copy link

same here :-(

Output:

undefined
undefined
(node:61714) UnhandledPromiseRejectionWarning: Error: Unsupported DID method: 'ethr'
at /Users/user/projekt/node_modules/ethr-did/node_modules/did-resolver/lib/resolver.js:42:12

@jmsofarelli
Copy link

The error also happens in the method verifyJWT() of 'did-jwt' library.

@froid1911
Copy link

froid1911 commented Feb 26, 2019

Someone posted a solution in chat:

Rob helped me to find the solution and I will post here:
"This can sometimes happen if you end up with multiple versions of the did-resolver package, and so ethr-did-resolver ends up being registered to the wrong copy of the root resolver. You can investigate further by running npm ls did-resolver and identify potential duplicates. Ensuring that all references are to the same version and deduped should resolve the issue — this may require updating one or more packages that depend on did-resolver."
In my case the result of npm ls did-resolver was:
uport-poc@1.0.0 /Users/sofarell/workspace/uport-poc

I downgraded my "did-jwt' to 0.0.8 and it worked fine!

@hsnhrn
Copy link

hsnhrn commented Aug 27, 2019

I am not able to sole it does anyone have any idea about this error while calling verifyJWT?
(node:3310) UnhandledPromiseRejectionWarning: Error: Unsupported DID method: 'ethr'

thanks alot!!

@mirceanis
Copy link
Contributor

mirceanis commented Aug 27, 2019

The did-jwt lib is being refactored to use a local configuration instead of a global.
(decentralized-identity/did-jwt#50)
This should fix the error of being registered to the wrong copy of the root resolver.

That being said, you could also probably fix this by using did-jwt (or even uport-credentials) to create and verify JWT instead of ethr-did.

@mirceanis
Copy link
Contributor

The root cause is that this library is not installing the ethr-did-registry on its own.
The underlying did-jwt lib does not use a default set of DID resolvers. Devs have to install each one they plan to use.
The upcoming changes in the way these resolvers are installed and used will make it possible for this library to use a local resolver configured with the same parameters.

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

@mirceanis
I'm trying to verify jwt using ethrDid.verifyJWT(jwt) but getting the following error:
UnhandledPromiseRejectionWarning: Error: Unsupported DID method: 'ethr'
here is my sample code:

// network config
const HttpProvider = require('ethjs-provider-http')
const Web3 = require('web3')
Web3.providers.HttpProvider.prototype.sendAsync = Web3.providers.HttpProvider.prototype.send
let provider = new Web3.providers.HttpProvider('http://localhost:8546')

const EthrDID = require('ethr-did');
const resolve = require('did-resolver').default;
const registerResolver = require('ethr-did-resolver').default

const didJWT = require('did-jwt')
const { SimpleSigner } = require('did-jwt')

// get accounts
//const accounts = await provider.eth.getAccounts();
const signer = SimpleSigner('0x92dd08591c87f6b860fd2bb4895d593f9f240a6f289883a7d5d625494eaeda1d')
const registry = '0xd3a1647be4fe9fab57ba0c4a8215cb8a927e5e16';
const address = '0x07b3fae112f54be9c1bd4477565e0366c41fc2f3';

const keypair = EthrDID.createKeyPair()
//Generating Ethr DID
const ethrDid = new EthrDID({ provider, registry, address });

let test = async () => {

    const delegate = await ethrDid.createSigningDelegate()
    const jwt = await ethrDid.signJWT({ claims: { name: 'Joe Lubin' } });
    console.log(didJWT.decodeJWT(jwt)); // this is successful
    //const { payload, issuer } = ethrDid.verifyJWT(jwt); // this throws error

}

test()

Dependencies:
"did-jwt": "0.0.8"
"did-resolver": "0.0.7"
"ethjs-provider-http": "^0.1.6"
"ethr-did": "^1.1.0"
"ethr-did-resolver": "^0.2.0"
"web3": "^1.2.1"

@mirceanis
Copy link
Contributor

mirceanis commented Aug 28, 2019

you also need to register the ethr-did-resolver
I see you are already importing it (const registerResolver = require('ethr-did-resolver').default).
The missing step is to call registerResolver({provider : provider, registry : registry})

Also, this line seems to be unused: const keypair = EthrDID.createKeyPair()
Unless you intend to sign something with that keypair, you should remove that line to avoid confusion.

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

@mirceanis thank you very much for your support.
there is still one issue:

const { payload, issuer } = ethrDid.verifyJWT(jwt);
console.log(payload); // returns undefined
console.log(issuer); // returns undefined

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

it is fixed:
we need to use async await method:
const { payload, issuer } = await ethrDid.verifyJWT(jwt);

@mirceanis
Copy link
Contributor

you may also want to upgrade to did-jwt@0.2.0 since it fixes an issue with global Buffer

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

@mirceanis
thank you so much for your support.
I upgraded to did-jwt@0.2.0 and ethrDid.signJWT and ethrDid.verifyJWT works fine.
However, didJWT.verifyJWT is not working.
here is the updated sample code:

....
const signer = didJWT.SimpleSigner('0x92dd08591c87f6b860fd2bb4895d593f9f240a6f289883a7d5d625494eaeda1d')
.....
// inside the async function

let jwt = '';
    didJWT.createJWT({ aud: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', exp: 1957463421, name: 'uPort Developer' },
        { issuer: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', signer }).then(response => {
            jwt = response
            console.log(jwt); // this works fine

            // this does not work
            let verifiedRespone = {};
            didJWT.verifyJWT(jwt, { audience: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3' }).then((response) => {
                verifiedRespone = response
                console.log(verifiedRespone);
            });
        });

The error is:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property '-1' of null at BN.bitLength

@mirceanis
Copy link
Contributor

you are experiencing this bug: decentralized-identity/did-jwt#14

to fix it add alg : 'ES256K-R' to the options for didJWT.createJWT

//....
const signer = didJWT.SimpleSigner('0x92dd08591c87f6b860fd2bb4895d593f9f240a6f289883a7d5d625494eaeda1d')
//.....
// inside the async function

let jwt = '';
    didJWT.createJWT({ aud: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', exp: 1957463421, name: 'uPort Developer' },
        { alg: `ES256K-R`, issuer: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', signer }).then(jwt => {
            console.log(jwt); // this works fine

            didJWT.verifyJWT(jwt, { audience: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3' }).then((verifiedRespone) => {
                console.log(verifiedRespone);
            });
        });

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

it throws the error : UnhandledPromiseRejectionWarning: Error: Signature invalid for JWT
the updated code is:

const { createJWT, verifyJWT, SimpleSigner } = require('did-jwt')
....
// with or without signer has same error
const ethrDid = new EthrDID({ provider, registry, address, signer });
....
let jwt = '';
    createJWT({ aud: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', exp: 1957463421, name: 'uPort Developer' },
        { alg: 'ES256K-R', issuer: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3', signer }).then(jwt => {
            console.log(jwt); // this works fine
            // this does not work
            verifyJWT(jwt, { audience: 'did:ethr:0x07b3fae112f54be9c1bd4477565e0366c41fc2f3' }).then((verifiedRespone) => {
                console.log(verifiedRespone);
            });
        });

@mirceanis
Copy link
Contributor

what network are you on?
is it a public network?

if you are using ganache, there seem to be some issues that prevent ethr-did-registry from working correctly (#33 (comment))

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

yes, this is ganache.

@m-yahya
Copy link

m-yahya commented Aug 28, 2019

I tested it with EWF Volta chain (https://energyweb.atlassian.net/wiki/spaces/EWF/pages/703201459/Volta+Connecting+to+Remote+RPC) running on my machine, but still the same error:
UnhandledPromiseRejectionWarning: Error: Signature invalid for JWT at verifyRecoverableES256K

@m-yahya
Copy link

m-yahya commented Aug 29, 2019

@mirceanis

// inside async function
const delegate = await ethrDid.createSigningDelegate()
    //console.log(delegate);
    registerResolver({ provider: provider, registry: registry })
    // sign and verify jwt
    const jwt = await ethrDid.signJWT({ claims: { name: 'Joe Lubin' } });
    console.log(decodeJWT(jwt));
    // this works fine with ganache
    // with volta, this throws error:
    // UnhandledPromiseRejectionWarning: Error: Signature invalid for JWT
    // at verifyRecoverableES256K
    const { payload, issuer } = await ethrDid.verifyJWT(jwt);

@mirceanis
Copy link
Contributor

@m-yahya please post an example of an invalid JWT, as well as the registry address you are using on volta

@mirceanis
Copy link
Contributor

Also, perhaps it is a timing issue, see #34

@mirceanis
Copy link
Contributor

Closing this since the original error (Error: Unsupported DID method: 'ethr') was resolved

@m-yahya
Copy link

m-yahya commented Aug 29, 2019

Also, perhaps it is a timing issue, see #34

we need a delay before executing verification.
here is working example:

// inside async function
// ....
// sign and verify jwt
    const jwt = await ethrDid.signJWT({ claims: { name: 'uPort Developers' } });
    console.log(decodeJWT(jwt));
    setTimeout(async function () {
        const { payload, issuer } = await ethrDid.verifyJWT(jwt);
        console.log(issuer);
    }, 2000)

@mirceanis
Copy link
Contributor

Just to be clear, the delay is needed somewhere between createSigningDelegate() and verifyJWT because createSigningDelegate() sends a transaction and that block needs to propagate to the node that responds to the calls made by verifyJWT (resolving the DID document).

So, if your flow requires some key delegation for signing but not immediately followed by verification, this delay will not be needed.

@gdollard
Copy link

I hate to drag this up again but when I call verifyJWT I still get: Error: Unsupported DID method: 'ethr'

I have created my EthrDID and registered my ethrDidResolver. I have even verified that the
resolver does indeed resolve my DID string and produce a DID document.

const didResolver = new Resolver(ethrDidResolver)

The signJWT returns a JWT as expected:

const helloJWT = await ethrDid.signJWT({hello: 'world'})
    console.log("JWT: ", helloJWT)

But the line below fails:
const {payload, issuer} = await ethrDid.verifyJWT(helloJWT).then(data => {console.log("Returned Data: ", data)}).catch(error => {console.log("Error when verifying JWT: ", error)})

This is doing my head in!
Any ideas ??

@gdollard
Copy link

same here :-(

Output:

undefined
undefined
(node:61714) UnhandledPromiseRejectionWarning: Error: Unsupported DID method: 'ethr'
at /Users/user/projekt/node_modules/ethr-did/node_modules/did-resolver/lib/resolver.js:42:12

Hi Frank, did you manage to resolve this? I'm currently having the same issue.

@mirceanis
Copy link
Contributor

@gdollard try passing the resolver to the verify method

const didResolver = new Resolver(ethrDidResolver)
const {payload, issuer} = await ethrDid.verifyJWT(helloJWT, didResolver).then(...)

@gdollard
Copy link

@mirceanis thanks for the reply. I am now getting the following error: "mnidOrDid.match is not a function"

using the following code:

const {payload, issuer} = await ethrDid.verifyJWT(helloJWT, {resolver: didResolver, audience: keyPair.address }).catch(error => {
        console.log("Error from verifyJWT: ", error.message)
    })

@gdollard
Copy link

OK, I have modified my code to directly use did-jwt for JWT creation verification. I understand ethr-did provides a layer of abstraction from this but I was having so many problems, mainly due to the data I was passing it was easier to debug from this lower level. I discovered my problem may have been due to the keyPair object I was using. I was hoping to use a key pair from one of my accounts via my web3 instance but for some reason JWT doesn't like it. When I use the object returned by EtherDID.createKeyPair() it works! I'm going to investigate further because surely this should work with my own correctly created account keyPair (as exported from my MetaMask account).
Thanks for your feedback @mirceanis

@mirceanis
Copy link
Contributor

I was hoping to use a key pair from one of my accounts via my web3 instance but for some reason JWT doesn't like it.

web3 signatures are different from JWT signatures, even if the same private key is in use so it wouldn't work with only your web3 provider.

For reference, in pseudocode web3 signatures are computed as
signHash(privKey, keccak(message))
while JWT signatures are computed as
signHash(privKey, sha256(message))


As a side-note, unfortunately there's not enough bandwidth now to investigate the issues you are facing, not even to update docs for this library. PRs are still welcome, of course.

@gdollard
Copy link

I was hoping to use a key pair from one of my accounts via my web3 instance but for some reason JWT doesn't like it.

web3 signatures are different from JWT signatures, even if the same private key is in use so it wouldn't work with only your web3 provider.

For reference, in pseudocode web3 signatures are computed as
signHash(privKey, keccak(message))
while JWT signatures are computed as
signHash(privKey, sha256(message))

As a side-note, unfortunately there's not enough bandwidth now to investigate the issues you are facing, not even to update docs for this library. PRs are still welcome, of course.

@mirceanis thanks for that information, much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

7 participants