This SDK combines the functionality of an Issuer and Verifier entities to work with UnumID's SaaS. For necessary account creation and API keys please email admin@unum.id.
SDK Functionality
The Server SDK uses the UnumDto type to facilitate handling many response body types while providing a reliable structure to access the result body and importantly the rolling JWT authToken.
{
"authToken": string;
"body": T;
}
Authentication
Every request detailed below requires a Bearer authToken
as a first parameter which is used to authenticate request to UnumID's SaaS on your behalf. As mention above this auth token updated upon every subsequent function call and should be read via the authToken
attribute and persisted accordingly for later requests.
Errors
Errors returned by UnumID's SaaS will also be wrapped in the UnumDto object so that the potentially updated authToken
can be retrieved. Validation errors which are created prior to any internal calls to UnumID's SaaS will be of type Error and are thrown. This is due to never making a network call with the provided authToken so no potential new authToken to pass back. For this reason we recommend wrapping all SDK calls in a try/catch.
Issuer
The Issuer functionality is used by a customer acting as an Issuer. It allows customers to perform actions such as issuing and revoking Credentials.
registerIssuer
Register an issuer corresponding to your customer UUID and issuer API key provided by UnumID. As a customer, you can register as many issuers as you like (or none at all), depending on your use case. Note, however, that you'll need a unique issuer API key for each one.
You should store the DID (did
) and encryption and signing key pairs (keys
) that this returns. You'll need these to issue credentials to users.
Parameters:
"name": string,
"customerUuid": string,
"apiKey": string
Response Body: RegisteredIssuer
{
"uuid": string,
"customerUuid": string,
"did": string,
"name": string,
"createdAt": string,
"updatedAt": string,
"keys": {
"signing": {
"privateKey": string,
"publicKey": string,
}
"encryption": {
"privateKey": string,
"publicKey": string,
}
}
}
issueCredential
Issue a credential to a Subject, also known as a User.
You need to provide your Issuer DID (created when you registered), as well as your signing and encryption private keys, which the Issuer uses to sign and encrypt the credential. You need to specify a credential type
, which verifiers will use to later request the credential from the user.
This returns a credential id
that should be stored for reference. For example, the credential id is required to revoke the credential if need be. We would recommend storing the entire credential indexed on the resultant credential id
. Note that there are also id fields within a credentialSubject
and credentialStatus
, but these are different. They refer to the subject DID and credential status identifier, respectively, as defined by the W3C spec [1],[2].
Important: The private keys never leave your app. This function, like all the others in this SDK, needs them in order to handle to cryptographic functionality on your behalf.
Parameters
"type": string || string[],
"issuer": string,
"credentialSubject": {
"id": string,
[key: string]: any,
},
"signingPrivateKey": string
"expirationDate"?: string,
Response Body: Credential
{
"@context": ["https://www.w3.org/2018/credentials/v1"],
"credentialStatus": {
"id": string,
"type": "CredentialStatus"
},
"credentialSubject": {
"id": string,
[key: string]: any,
},
"issuer": string,
"type": string[],
"id": string,
"issuanceDate": string,
"expirationDate": string,
"proof": Proof
}
updateCredentialStatus
Update a credential, i.e. make it invalid.
You need to provide the credential id
(created when you issued the credential) and a CredentialStatusOptions status
. Currently the only valid status are: verified and revoked.
export type CredentialStatusOptions = 'valid' | 'revoked';
Parameters
{
"credentialId": string
"status": CredentialStatusOptions
}
Response Body: Empty. If unsuccessful and exception will be thrown.
{}
Verifier
The Verifier functionality is used by a customer acting as a verifier. Most importantly, it allows customers to send PresentationRequests to the UnumID mobile SDK and to verify the encrypted Presentation responses.
registerVerifier
Register a verifier corresponding to your customer UUID and verifier API key that UnumID provides. As a customer, you can register as many verifiers as you like (or none at all), depending on your use case. Note, however, that you'll need a unique verifier API key for each one.
You should store the DID (did
) and signing key pair (keys
) that this returns. You'll need these to create requests for (presentations of) credentials from users.
Parameters
"name": string,
"customerUuid": string,
"url": string,
"apiKey": string
Response body: RegisteredVerifier
{
"uuid": string,
"customerUuid": string,
"did": string,
"name": string,
"createdAt": string,
"updatedAt": string,
"keys": {
"signing": {
"privateKey": string,
"publicKey": string,
}, "encryption": {
"privateKey": string,
"publicKey": string,
}
}
sendRequest
Create a request for (a presentation of) credentials from a user.
You need to provide your verifier DID (created when you registered) and the UUID of the holder app from which the user can share the data. You also need to provide your signing private key, which the SDK uses to sign the request.
Important: The signing private key never leaves your app. This function, like all the others in this SDK, is solely using it to handle to cryptographic functionality on your behalf.
To request credentials, you need to populate one or more CredentialRequest objects, defined in the UnumID generic types project and shown below.
export interface CredentialRequest {
type: string;
issuers: string[];
required?: boolean;
}
If you list more than one acceptable issuers
(entities that issued the desired credential type), the user can share a credential issued by any of the ones listed.
Parameters
"verifier": string,
"credentialRequests": CredentialRequest[],
"signingPrivateKey": string,
"holderAppUuid": string,
"expiresAt"?: string,
"metadata"?: object
Response Body: PresentationRequestPostDto
{
"presentationRequest": {
"uuid": string,
"createdAt": string,
"updatedAt": string,
"expiresAt": string,
"verifier": string,
"credentialRequests": CredentialRequest[],
"proof": Proof,
"metadata": object
},
"verifier": {
"name": string,
"did": string,
"url": string
},
"issuers": {
"IssuerDid:string": {
"name": string,
"did": string
}
},
"holderApp": {
"name": string,
"uriScheme": string,
"deeplinkButtonImg": string
},
"deeplink": string,
"qrCode": string
}
verifyPresentation
Handles decrypting the encrypted presentation and verifies the signatures are valid.
You need to be able to receive presentations from users and pass them to this function. To do this, you need to create a /presentation
endpoint that conforms to our OpenAPI specification. The Unum ID cloud sends encrypted presentations to this endpoint, which should pass those presentations to the verifyPresentation
function to be decrypted and verified.
You need to provide:
- your verifier did
- your verifier encryption private key
- encrypted presentation (received at
/presentation
endpoint) - (optional, but recommended) presentation request (received at
/presentation
endpoint)
The fist two are returned by registerVerifier
.
Important Although the mobile SDK sends the presentations directly to UnumID's SaaS, UnumID never has access to the credentials within the presentation. The mobile SDK encrypts all presentations with the presentation requesting verifier's public key, to which the requestor is the only ones with necessary decryption private key, the Verifier's encryptionPrivateKey
, an attribute created with the registerVerifier call.
Note presentationRequest
is optional in order for the server sdk can handle verifying presentations that may not have a corresponding request. However, if presentationRequest
is supplied from UnumID's SaaS via the /presentation
endpoint, it is strongly recommended that it is provided as it performs additional validation checks on your behalf.
Parameters
"encryptedPresentation": EncryptedData,
"verifierDid": string,
"encryptionPrivateKey": string
"presentationRequest"?: PresentationRequestDto
Response Body: DecryptedPresentation
{
"isVerified": boolean;
"type": 'VerifiablePresentation' | 'NoPresentation'
"presentation": Presentation | NoPresentation,
"message"?: string;
}
sendSms
Use to send a deep link to a user by SMS. The message will be delivered from an UnumID associated phone number. You can of course use your own SMS sending service if you prefer.
To request (a presentation of) credentials from a user, you first create the request object and receive a deep link that references it. The user need to receive this deep link, which will open the correct app on their phone and prompt them to share the credentials. SMS is one convenient channel.
Parameters
{
"to": string,
"msg": string
}
Response Body: Empty. If unsuccessful and exception will be thrown.
{}
sendEmail
Use to send a deep link to a user by email. The message will be delivered from no-reply@unum.id. You can of course use your own email sending service if you prefer.
To request (a presentation of) credentials from a user, you first create the request object and receive a deep link that references it. The user need to receive this deep link, which will open the correct app on their phone and prompt them to share the credentials. Email is one convenient channel, though keep in mind that the user will need to click the link from their phone for the deep link to work.
Tip: JSON special characters such a double quote or backslash in the subject
or htmlBody
fields will need to be escaped with a single backslash (\), i.e. "the best org in the country" must be \"the best org in the country\".
Parameters
{
"to": string,
"from": string,
"replyTo": string,
"subject": string,
"textBody"?: string,
"htmlBody"?: string,
}
Response Body: Empty. If unsuccessful and exception will be thrown.
{}
checkCredentialStatus
Used to check the status of a credential.
The status
attribute of the response is of type CredentialStatusOptions. Currently the only valid status are: verified and revoked.
export type CredentialStatusOptions = 'valid' | 'revoked';
Parameters
{
"credentialId": string,
}
Response Body: CredentialStatusInfo. If unsuccessful and exception will be thrown.
{
"createdAt": Date;
"updatedAt": Date;
"credentialId": string;
"status": CredentialStatusOptions;
}
Other Information
Distribution
This project is publicly published on the official npm registry. For example it can be pulled with, npm i @unumid/server-sdk
or yarn add @unumid/server-sdk
.
Releases
Releases and publishing to NPM is automated via Github Actions CI job. In order to trigger a release one should push a git tag with a preceding v
with semver notation, ie v1.1.1, to the main
branch. This will trigger the CI job to bump the package version, generate typedocs, publish to NPM, make a release commit, and make a Github Release. The message of the git tag will be the release message so please make it meaningful. For example, git tag v1.2.0 -m "Updated the SDK with a new CI job" && push origin v1.1.1
.
Global Dependencies
- NodeJS v14.0.0 or higher, preferably v14.15.0 or higher
- yarn
Logging
Logs level defaults to Info. One can set to debug for more information via the environment variable LOG_LEVEL, i.e. LOG_LEVEL=debug. We are using standard NPM log levels. More details on the various log levels here.
The logs default to stdout so can be aggregated using any log provider you would like from disk.
Documentation
High level technical documentation can be found here which is served via Docusaurus. More detailed generated from source documentation can be found here which is served via repo specific Github pages via the /docs folder of the main branch.
In order to generate the Typedoc documentation from the source code run the createTypedocs.sh
script.