5. Credential-based Communication Flows

This section offers a detailed overview of the interaction flows supported by the Jolocom Library.

Identities can interact in incredibly complex ways. We currently support a number of quite simple interaction flows, and intend to greatly expand the list in future releases.

Note

The following sections assume you have already created an identity. If youhave not yet created an identity, check out the Getting Started section.

5.1. Request credentials from another identity

Many services require their users to provide certain information upon signing up. The Jolocom library provides a simple way for services to present their requirements to users who wish to authenticate through defining and presenting what we call a credential request. First, the aforementioned request must be generated:

Create a Credential Request

// An instance of an identityWallet is required at this point
const credentialRequest = await identityWallet.create.interactionTokens.request.share({
  callbackURL: 'https://example.com/authentication/',
  credentialRequirements: [{
    type: ['Credential', 'ProofOfEmailCredential'],
    constraints: []
  }],
}, password)

Note

Documentation on constraints and how they can be used to create even more specific constraints will be added soon.

Note

For further documentation and examples explaining how to create and send credential requests, check the API documentation, the demo service implementation, the integration tests, and finally this collection of examples.

The easiest way to make the credential request consumable for the client applications is to encode it as a JSON Web Token. This allows us to easily validate signatures on individual messages, and prevent some replay attacks.

In order to make the credential request consumable by the Jolocom SmartWallet the JSON Web Token must further be encoded as a QR code that can be scanned by the wallet application. The credentialRequest can be encoded as follows:

// Will be deprecated in future releases in favor of more user-friendly and intuitive ways to encode data

const jwtEncoded = credentialRequest.encode()
const QREncoded = new SSO().JWTtoQR(jwtEncoded)

Further encodings will be added as the architecture continues to mature.

Consume a Signed Credential Request

Once the encoded credential request has been received on the client side, a corresponding credential response should be prepared and sent:

const credentialRequest = JolocomLib.parse.interactionToken.fromJWT(enc)
identityWallet.validateJWT(credentialRequest)

Note

The validateJWT method will ensure the credential is not expired, and that it contains a valid signature.

Create a Credential Response

Once the request has been decoded, we can create the response:

/**
 * The callback url has to match the one in the request,
 * will be populated autmoatically based on the request starting from next major release
 */

const credentialResponse = awaitidentityWallet.create.interactionTokens.response.share({
    callbackURL: credentialRequest.payload.interactionToken.callbackURL,
    suppliedCredentials: [signedEmailCredential.toJSON()] // Provide signed credentials of requested type
  },
  encryptionPass, // The password to decrypt the seed for key generation as part of signing the JWT
  credRequest // The received request, used to set the 'nonce' and 'audience' field on the created response
)

The credential supplied above (conveniently) matches what the service requested. To ensure that no credentials other than those corresponding to the service requirements are provided, the following method to filter can be used:

// We assume the client application has multiple credentials persisted in a local database
const localCredentials = [emailAddressSignedCredential, phoneNumberCredential]
const localCredentialsJSON = localCredentials.map(credential => credential.toJSON())

// The api will change to take instances of the SignedCredential class as opposed to JSON encoded credentials
const validCredentials = credentialRequest.applyConstraints(localCredentialsJSON)

console.log(validCredentials) // [emailAddressSignedCredential]

Once the credential response has been assembled, it can be encoded and sent to the service’s callback url:

const credentialResponseJWT  = credentialResponse.encode()

Consume a Signed Credential Response

Back to the service side! The credential response encoded as a JSON Web Token has been received and the provided data is ready to consume. First, decode the response:

const credentialResponse = await JolocomLib.parse.interactionToken.fromJWT(receivedJWTEncodedResponse)
await identityWallet.validateJWT(credentialResponse, credentialRequest)

Note

The validate method will ensure the response contains a valid signature, is not expired, lists our DID in the aud [audience] section, and contains the same jti [nonce] as the request.

After decoding the credential response, verify that the user passed the credentials specified in the request:

/**
 * We check against the request we created in a previous step
 * this requires the server to be stateful. We are currently
 * expolring alternatives.
 */

const validResponse = credentialResponse.satisfiesRequest(credentialRequest)
const registry = JolocomLib.registries.jolocom.create()

if (!validResponse) {
  throw new Error('Incorrect response received')
}

const providedCredentials = credentialResponse.getSuppliedCredentials()

/** Eventually a helper will be provided to take care of this */
const signatureValidationResults = await Promise.all(providedCredentials.map(credential => registry.validateSignature(credential)))

if (signatureValidationResults.every(result => result === true)) {
  // The credentials can be used
}

5.2. Offering credentials to another identity [EXPERIMENTAL]

In some cases, an agent might want to issue another agent a signed credential. We are currently developing a siple protocol to facilitate this interaction. As of now, an early version is already supported through the Jolocom Library.

Crete a Credential Offer

Firstly, the agent offering the attestation must create a credential offer:

const credentialOffer = await identityWallet.create.interactionTokens.request.offer({
  callbackURL: 'https://example.com/receive/...',
  instant: true,
  requestedInput: {}
})

The endpoint denoted by the callbackURL key will be pinged by the client device with a response to the offer.

The instant (will be used to signal if the credential will be available right away) and requestedInput (will be used for requesting additional information, e.g. a valid id card to receive a driver license credential) are not used as of now, and will be supported once we implement verification requests.

Consume a Credential Offer

On the client side, we can decode and validate the received credential request as follows:

const credentialOffer = JolocomLib.parse.interactionToken.fromJWT(enc)
identityWallet.validateJWT(credentialRequest)

Note

The validateJWT method will ensure the credential is not expired, and that it contains a valid signature.

Create a Credential Offer Response

The easiest way to create a response is:

const offerResponse = await identityWallet.create.interactionTokens.response.offer({
  ....interactionToken.toJSON()
}, secret, credentialOffer)

Note

The response simply replays all fields in the response. With the introduction of verification requests this will no longer be the case.

Transferring the credential to the user

The credential offer response is sent back to the service, which in return generates the credential and sends it to the client. There are a few way to accomplish the last step, currently the service simply issues a CredentialResponse JWT containing the credentials. An example implementation can be found here.

5.3. What next?

With the reasoning behind the credential request and response flows unpacked, it’s time to put it all to the test! Head to the next section to learn how to set up your own service for interacting with Jolocom identities.