Recipes
Recipes allow planning the credential issuance and document printing process in Document Rails.
Usually, recipes are pre-configured for specific processes (document types, forms, etc.), and are repeatedly utilized later for printing many documents that follow the same schema.
flowchart LR
IC[Input credentials] -->|Provided directly| R[Recipe]
CS[Credential subject IDs] -->|Provided directly| R
OI[Output credential IDs] -->|Provided directly| R
EI[External user IDs] -->|Provided directly| R
SL[Status lists] -->|Provided directly| R
SK[Signing keys] -->|Provided directly| R
IC .->|Customizable process| IW
CS .->|Customizable process| IW
OI .->|Customizable process| IW
IW[Inbound webhooks] .->|Requested on demand| R
R --> OC[Output credentials]
R --> PD[Printed PDF document]
Recipes have to be configured before the printing process.
When printing recipes be aware that the process is asynchronous, meaning that you will only receive the request_id identifier, which you can later utilize to correctly identify incoming requests on configured outbound webhooks.
Creating recipes
Recipe definitions are used to define how the issuance process should proceed - which credentials and documents should be generated, how input data should be provided, what webhooks can Document Rails communicate with during the process.
Specifically, the following parameters are configured during the recipe creation:
-
Mapping of input credential variables to template variables. This is used to express situations like "map first and last names from this JSON object to this .docx template".
-
Mapping of input credential variables to output credential variables. Example mapping would include a scenario like "map first and last names from this JSON object to one W3C and one SD-JWT credential".
-
Passthrough credentials. With this configuration, you can express flows that pass existing signed information into new documents for source tracking purposes.
-
Inbound webhooks, which are utilized to provide input data to the issuance process using external sources.
-
Outbound webhooks, whose purpose is to be used to send newly issued credentials and documents to.
-
Embedded OID4VCI credential offer. Useful to embed mobile credential offers into regular documents to allow users to seamlessly transition from paper documents to digital credentials.
-
Credentials to be used as QR code and barcode credentials. This allows verification of digitally signed claims on printed paper documents.
All parameters are optional and highly customizable. Some examples include:
-
A recipe that "prints" a paper credential in the PDF format with a W3C credential embedded within a QR code.
-
A recipe with multiple output credentials and an attached OID4VCI credential offer, allowing users to select which credential they want to issue during a particular issuance session.
-
A recipe with configured passthrough credentials to create a chain of trust.
import { createRecipe, getCredential, getTemplate } from "@vaultie/document-rails";
// For clear demonstration of how identifier mapping works in recipes,
// we can create regular objects that map from the associated entity name to its identifier.
//
// You can omit this part in your code, but for documentation purposes
// it should make clear which fields are utilized in recipes.
//
// Graphical interfaces for Document Rails should usually represent this part
// as nodes that can be connected to each other.
const inputCredentialVars = await getCredential(
client,
accessToken,
organizationId,
exampleInputCredentialId
).then(({ credential_vars }) => {
// Convert credential_vars into an object of the following structure:
// credential_var_name -> credential_var_id
return Object.fromEntries(credential_vars.map((val) => [val.var_key, val.id]));
});
const outputCredentialVars = await getCredential(
client,
accessToken,
organizationId,
exampleOutputCredentialId
).then(({ credential_vars }) => {
// Same as before, convert credential_vars into an object of the following structure:
// credential_var_name -> credential_var_id
return Object.fromEntries(credential_vars.map((val) => [val.var_key, val.id]));
});
const templateVars = await getTemplate(
client,
accessToken,
organizationId,
templateId
).then(({ template_vars }) => {
// Similar to credential variable mapping, we map template variable name to its id.
return Object.fromEntries(template_vars.map((val) => [val.var_name, val.id]))
});
// Finally, create a recipe.
//
// Recipes are re-usable, so this setup is usually performed once per desired scenario.
const response = await createRecipe(
client,
accessToken,
organizationId,
{
// Template used for rendering the output PDF document.
template_id: templateId,
// Map input credential variables to template variables.
//
// This instructs Document Rails to assign values of input credential variables
// into the final template.
templates: {
// Document Rails accepts an id -> id mapping.
//
// For this example, we map the input credential "first_name" field
// to a template variable "firstName".
[inputCredentialVars["first_name"]]: [templateVars["firstName"]],
// You can also map input credential variables to multiple template variables at the same time.
[inputCredentialVars["last_name"]]: [
templateVars["lastName"]
templateVars["senderLastName"]
],
},
// Map input credential variables to output credential variables.
//
// Notice that with Document Rails it's possible to not only assign the same variable to
// multiple different output variables, but to different output credentials altogether.
output_credentials: {
// Document Rails accepts an id -> id mapping.
//
// In this example, we can map either a W3C credential or plain JSON data to an MDoc credential.
//
// Document Rails can easily ingest existing data or even issued credentials
// and output entirely new credentials based on that.
[inputCredentialVars["first_name"]]: [outputCredentialVars["iso.org.18013.5.1::given_name"]],
// Just like with template variables, we can map multiple
// credential input variables to multiple credential output variables.
//
// In fact, we can even map one input field into two output fields of two completely different credentials.
[inputCredentialVars["last_name"]]: [
outputCredentialVars["iso.org.18013.5.1::last_name"],
outputCredentialVars["com.example.custom_credential::sender_last_name"],
],
},
// Configure inbound webhooks for this specific recipe.
//
// For example, if the credential with the identifier on the left-hand side of this
// object is missing, Document Rails is going to contact the inbound webhook with the identifier
// from the right-hand side of this object.
inbound_webhooks: {
// Document Rails accepts an id -> id mapping.
[inputCredentialId]: [inboundWebhookId],
// You can assign multiple inbound webhooks for a credential.
//
// This adds redundancy to the issuance process.
[outputCredentialId]: [
inboundWebhookId,
differentInboundWebhookId
],
},
// Configure outbound webhooks for this specific recipe.
//
// Outbound webhooks are used to communicate issued credentials/documents
// with your application, or to signal about an occured error.
//
// You can assign multiple outbound webhooks for a recipe,
// in which case Document Rails will communicate will multiple
// servers to deliver the information about the issuance process.
outbound_webhooks: [outboundWebhookId],
// Passthrough credentials are utilized to move input credentials into output credentials as-is,
// without changing the signature. This is particularly useful with W3C input credentials,
// when you are invoking Document Rails after acquiring a verifiable credential from some other source.
//
// This functionality allows you to carry source credentials with issuer information
// for chain-of-trust preservation.
passthrough_credentials: [],
// Offered credentials are included within the generated OID4VCI credential offer URL.
//
// Only credentials that have their OID4VCI metadata configured are considered for
// inclusion in the final generated credential offer.
offered_credentials: [outputCredentialId],
// OID4VCI credential offer to embed into the resulting paper document.
//
// See the OID4VCI documentation for more information.
oid4vci_credential_offer_id: credentialOfferId
}
);
Printing recipes
After initializing at least one recipe definition, it is possible to start the credential issuance process.
This step involves utilization of an existing recipe definition to identify how exactly the issuance flow should proceed. Since all instructions are already encoded within the original definition, we may only provide some supplemental data here.
To start printing, you must provide issuer_configurations field value, which identifies signing keys used for issuance of different credential kinds.
Additionally, you may optionally provide the following data when printing existing recipes:
-
Input credentials, which are used as a claim source for new credentials. Fetched from inbound webhooks if not provided.
-
Output credential identifiers, used to uniquely identify a given digital credential. Fetched from inbound webhooks if not provided.
-
Credential subject identifiers, embedded into output credentials to bound them to a given holder. Fetched from inbound webhooks if not provided.
-
Status lists, which are used to publish information about credential revocation. If not provided, relies on automatic status list management for status list allocation.
-
Issuance and expiration date overrides. By default, Document Rails issues credentials which are valid for a year.
-
Existing resources (such as PDF or PNG files), which can be used instead of the pre-configured template to apply the C2PA manifest.
import { printRecipe } from "@vaultie/document-rails";
const response = await printRecipe(
client,
accessToken,
organizationId,
recipeId,
{
// Input credentials.
//
// If an input credential is missing, it is fetched from an inbound webhook.
// If all attempts to fetch an input credential fail, the printing process will error out.
credentials: {
// In this case, we utilize a JSON input credential.
//
// W3C input credentials require a signed existing credential.
// See "Input credentials" documentation for more information.
[inputCredentialId]: {
first_name: "Test"
}
},
// Output credential identifiers.
//
// Missing output credential identifiers are fetched using an inbound webhook.
// If all attempts to fetch an output credential identifier fail, the printing process will error out.
output_credential_ids: {
[outputCredentialId]: "https://example.com/credentials/123-456-789"
},
// Output credential subject identifiers.
//
// These identifiers are used to define a credential recipient/subject.
// Different credential kinds utilize different credential subject identifier types.
// Consult credential kind-specific documentation for more information.
//
// Missing credential subject identifiers are fetched using an inbound webhook.
credential_subject_ids: {
// For this example, let's assume that the output credential is an MDoc credential.
//
// MDoc credentials use JWKs to identify credential subjects.
[outputCredentialId]: {
alg: 'EdDSA',
kty: 'OKP',
crv: 'Ed25519',
x: 'HltP0A_mCooS0Vv7y82mRYproNRcudqp0jNLUdSmOfI'
}
}
// Issuer configurations field is utilized to select
// signing keys for different credential kinds and for the C2PA manifest.
//
// All issuer configurations are optional if you are not utilizing
// the associated credential kind during the recipe printing process.
issued_configurations: {
w3c: w3cKeyId,
mdoc: mdocKeyId,
jwt: jwtKeyId,
c2pa: c2paKeyId,
},
// Status list identifiers.
//
// Optional if the automatic status list management is enabled, required otherwise.
status_lists: {
// Make sure the provided status list matches the credential kind it is used for.
//
// Consult credential kind-specific documentation for information about supported status lists.
[outputCredentialId]: statusListId,
},
// C2PA configuration.
//
// Optional, including all the fields within the object.
c2pa_configuration: {
// Title of the newly generated asset.
//
// When omitted, Document Rails selects a generic asset title.
title: "Example document"
},
// Optionally, you may specify issuance and expiration terms instead of using default values.
//
// By default, Document Rails issues credentials that are valid from today's date for one year.
// Issuance date is specified as a UTC Unix timestamp in seconds.
issuance_ts: 1893456000,
// Expiration date is specified as "days from the issuance date".
validity_term: 30,
// Existing PDF or PNG resource as a file blob.
//
// Optional, allows overriding the pre-configured template generation.
resource: "...",
// Existing assets to include as parent ingredients of thew newly generated C2PA asset.
//
// Optional, accepts an array of `File` instances.
ingredients: [
// ...
],
}
);