Home

Awesome

kotlin-did-jwt

CircleCI Twitter Follow

This is the Kotlin implementation of the basic JWT methods for DID-JWTs

FAQ and helpdesk support

did-jwt

The kotlin-did-JWT library allows you to sign and verify JSON Web Tokens (JWT) using ES256K, and ES256K-R algorithms.

Public keys are resolved using the Decentralized ID (DID) of the signing identity of the claim, which is passed as the iss attribute of the encoded JWT.

DID methods

We currently support the following DID methods:

Defaults are automatically installed but you can customize to fit your needs.

Support for other DID methods should be simple. Write a DID resolver supporting the DIDResolver interface. Install it using

val resolver : DIDResolver = DIDResolver.Builder
.addResolver(ethrDidResolver)
.addResolver(/*...*/)
.build()

Once you've verified that it works, feel free to advertise it in the list above so people can find it.

If your DID method requires a different signing algorithm than what is already supported, please create a PR.

Installation

The libraries built here are distributed through jitpack

In your main build.gradle file, add:

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
        //...
    }
}

In your application build.gradle file, add:

def did_jwt_version = "0.4.0"
dependencies {
    //...
    implementation "com.github.uport-project.kotlin-did-jwt:jwt:$did_jwt_version"
}

Example

1. Create a did-JWT

In practice you should secure the key passed to KPSigner. The key provided in code below is for informational purposes.

val jwt = JWTTools()
//...
val payload = mapOf(
        "claims" to mapOf("name" to "R Daneel Olivaw")
)

val signer = KPSigner("0x54ece214d38fe6b46110a21c69fd55230f09688bf85b95fc7c1e4e160441ece1")
val issuerDID = "did:ethr:${signer.getAddress()}"

val token = jwt.createJWT(payload, issuerDID, signer)

2. Decode a did-JWT

Try decoding the JWT. You can also do this using jwt.io

val (header, payload, sig) = jwt.decodeRaw("eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NkstUiJ9.eyJjbGFpbXMiOnsibmFtZSI6IlIgRGFuZWVsIE9saXZhdyJ9LCJpYXQiOjEyMzQ1Njc4LCJleHAiOjEyMzQ1OTc4LCJpc3MiOiJkaWQ6ZXRocjoweDQxMjNjYmQxNDNiNTVjMDZlNDUxZmYyNTNhZjA5Mjg2YjY4N2E5NTAifQ.o6eDKYjHJnak1ylkpe9g8krxvK9UEhKf-1T0EYhH8pGyb8MjOEepRJi8DYlVEnZno0DkVYXQCf3u1i_HThBKtAA")

The decoded payload resembles:

mapOf(
    "claims" to mapOf("name" to "R Daneel Olivaw"),
    "iat" to 1.2345678E7,
    "exp" to 1.2345978E7,
    "iss" to "did:ethr:0x4123cbd143b55c06e451ff253af09286b687a950"
)

You can also use jwt.decode("<token>") to get a JwtPayload object instead of a map but that is a more rigid structure and will be phased away in future releases.

3. Verify a did-JWT

val resolver = EthrDIDResolver.Builder()
                               .addNetwork(EthrDIDNetwork("<name>", "<registryAddress>", "<JsonRPC>"))
                               .build()
                               
val payload : JwtPayload = JWTTools().verify("<token>", resolver)

If the token is valid, the method returns the decoded payload, otherwise throws a InvalidJWTException or JWTEncodingException

This behavior is subject to change in an upcoming release The verify() method will return a higher level abstraction that will contain the payload and more.

The function requires a DIDResolver which will be used to resolve DIDs during the verification

Verifying a token means checking that the signature was produced by a key associated with the issuer DID (iss field).

This association is resolved by a DID resolver, which can produce a DIDDocument listing various public keys and service endpoints for a given DID.

Audience verification

If the token contains a non null aud field, an additional soft-check is performed to match the verification against an intended audience. This same aud DID must be supplied to the verify() method for the token to be marked as valid (after passing all the cryptographic checks as well).

Generally your app will have its own DID which should always be passed to the verify method so that only tokens intended for your app are considered valid.

CHANGELOG