Updated: Sep 10
In my last blog, I introduced you to Verifiable Credentials (VCs) and Decentralized Identifiers (DIDs). In this blog, I want to show you how you can issue your own VCs using the Microsoft public preview of their Verifiable Credentials (VCs) service. To do this, we will use the Microsoft example apps, which are available on GitHub. This series' final blog will look at how DIDs can be anchored in decentralised transaction ledgers using ION and the Bitcoin blockchain.
I started with proposing three initial blogs, and I have updated this to five:
Issuing DIDs and VCs with the Microsoft example app and Authenticator (This one)
DIDs and Decentralized Transaction Ledgers
Subject: Currently under NDA
By the end of this blog, you will understand how VCs are issued and verified. Please make sure you are familiar with the first blog before proceeding.
Microsoft has provided a tutorial which you can find here. I am basing this blog on the tutorial but will show you what is really going on.
The Microsoft example app and the Verifiable Claims SDK are written in Node.js. I am pitching this blog at IT Pros and assuming that the reader is a competent IT admin but knows nothing about Node.js or building the development environment. I will not teach you Node.js but will show you how to modify the code samples to better understand what's going on under the hood.
I am assuming you have a reasonable understanding of OpenID Connect and ID Tokens. If you need help in these topics, watch my webinar on "Federated Identity Authentication and Authorization with OpenID Connect and OAuth2.0" or better still come on my identity masterclass https://learn.xtseminars.co.uk/. It would be great to meet you.
If you want a visionary view of the future of identity I am doing a key note at the online HIP Conference on 1st July 2021. Join and be inspired to step into the future of identity.
The conference is free and has great sessions and speakers. Sign-up today
Preparing your environment
I recommend you create a Windows 10 VM to host your development environment. This will provide you with a sandbox environment for installing all the tools and development code. The Microsoft documentation for the tutorial is a little sparse when setting up the environment, especially if you are new to GitHub and Node.js. So let me help you. When installing the required apps, choose all the default settings unless otherwise specified below.
Download and install Visual Studio Code from here: https://code.visualstudio.com/Download
Download and install GIT from here: https://gitforwindows.org/
Download and install (see next paragraph) Node.js from here: https://nodejs.org/en/download/
To successfully run the node package manager (npm), you will need Python, and the Visual Studio Build Tools. During the Node.js installation, you can choose the option to install these tools along with Chocolatey. Alternatively, you could install Python, and the Visual Studio Build Tools separately. For the blog, I chose the Chocolatey option.
After installing the tools, sign out and sign in to set the appropriate paths variables.
Git is an open-source version control system. Files can be committed to a repository (storage) and then managed, including rolling back changes to a particular version and cloning. The repository could be local or remote. GitHub is a very popular remote repository where anyone can sign-up and host a public or private repository for free. GitHub is extensively used to make open-source projects publicly available. GitHub makes money through hosting, paid for, full featured private repositories.
Open a command prompt, and you can check the versions of the installed components using:
My version 14.16.1
My version 3.9.4
My version 2.31.1.windows.1
Now we have the tools, we can download the code samples, build the code (automatically installing the necessary modules including the VC SDK) and run the code.
The code will be executed locally on your Windows 10 VM. The authenticator app must be able to connect to the code using HTTPS. The Microsoft sample recommends using Ngrok to act as a reverse proxy providing a public URL through which your code can be accessed.
Download the Ngrok Zip from here: https://ngrok.com/download
Extract it to a suitable location, I placed it here: C:\ngrok
I am going to create a directory structure for running the sample code as follows:
Open a command prompt and switch to the version0 directory, and clone the code from GitHub using:
Examine the cloned code, and you will see an active-directory-verifiable-credentials folder and below that an issuer and a verifier folder. The code samples are run from each of these folders.
We'll leave version0 as a clean copy if we want to refer back to anything once we start making changes. Copy the active-directory-verifiable-credentials folder to the version1 folder.
In the command prompt window, switch to the version1\....\issuer folder and run:
Node Package Manager (NPM) builds the project, integrating external modules, including the Verifiable Credentials SDK. The modules that a project depends on are defined in package.json. When you run npm install, all the packages and their dependencies are added to the node_modules folder.
While the environment is being built, you will see some warning messages which you can ignore.
Now we can run the issuer app. To simplify examining the code and executing the app, let's do this from within VS Code. Open VS Code and using File | open Folder, open the issuer folder: c:\vcs\version1\active-directory-verifiable-credentials\issuer
From the menu bar, use Terminal | New Terminal to open a terminal window. In the terminal window, run the issuer app using:
If prompted by Defender to allow firewall access for Node.js, you do not need to enable it.
You will notice in the VS Code console window it reports: "Example issuer app listening on port 8081!". The example app has created a website and is listening on port 8081. If you want to see it running, you can browse to http://localhost:8081
The website must be available to the Microsoft Authenticator app, and for this, we use Ngrok. Open a new command prompt. Switch to the c:\ngrok directory and execute.
ngrok http 8081
You will see something similar to this:
You can run Ngrok, as an unregistered user, registered user, or paying user. Take a look at https://ngrok.com/pricing for more details.
When using Ngrok with the verifier app, you may receive a message about too many connections.
Use your browser (not your mobile) to connect to the HTTPS endpoint, in my example
You will see:
Click on Get credentials, and a QR code is shown. The Microsoft Authenticator app is used to scan the QR code.
The following steps will tell you all you need to know to add and manage a VC in your user agent (wallet).
If this is the first time you have added a VC, you will need to click Add account | Other account… you can then scan the QR code. The QR Code informs the Authenticator where it can retrieve the issuance request. The request defines the VC type that is being requested, lots more detail soon. As an alternative to using a QR Code, if the website is accessed directly from a mobile browser, a deep-link is used to trigger the Authenticator and the issuance request retrieval.
The first time you add a VC, you will see the Get started option and the Link to the Azure Preview Terms. Once you click Get started, you will see the card for the requested credential and asked to add it.
The credential that is being asked for is specified in an issuance request. The requester has a digital identity and has signed the issuance request using their private key. The requestor's DID is contained in the request, and the associated public key, contained in the DID document, is used to verify the signature. Hopefully, you have read the introduction to this series of blogs and will remember that a DID can be verified as belonging to an organisation via a DNS binding. The Authenticator has checked the signature and the DNS binding and has added the "Verified" icon for did.woodgrovedemo.com.
You may be wondering where the details for the displayed card have come from. The Authenticator has downloaded these details from the Azure AD VC service. The manifest defines how the card should be displayed, the required credentials and where the credentials can be obtained.
Credentials can be :
Taken from claims in an ID Token
The user signs in to an OpenID Connect identity provider, and an ID Token is issued. Claims in the ID Token are mapped to credentials in the new VC.
Taken from other VCs
Credentials in other VCs that the user owns are mapped to the new VC.
Using the Authenticator, the user defines the values for each of the credentials in the new VC. The user (subject) will sign the VC.
The values for credentials are statically defined.
In the example, you are being asked to sign in to a B2C directory. You have probably guessed, in this instance, the credentials are being taken from an ID Token.
Click the option to sign up now and create an account.
Once you have created the account, you are automatically signed in and can add the credential. You will now be in a position to present the VC to a verifier. More on the verification process soon.
Notice in step 9 two new icons are showing at the bottom right-hand side. The round icon starts the QR code scanner for VC issuance and verification requests. The Credentials icon switches from the other Authenticator functions and allows you to view your VCs.
Once you have a VC, you can click on the card for more details. Click on the three vertical dots to deactivate, activate or delete a card. A deactivated card cannot be presented.
I promised you some more details, so here we go!
When you run app.js, it is running on Node.js with Express. Express is a framework that simplifies the creation of web applications. Our website is listening on port 8081, and we are making it available via a public endpoint via Ngrok.
The request is built based on a credential type and manifest. If you look at the code for issuer/apps.js you will see two constants have been defined:
/////////// Set the expected values for the Verifiable Credential
const credential = 'https://beta.did.msidentity.com/v1.0/3c32ed40-8a10-465b-8ba4-0b1e86882668/verifiableCredential/contracts/VerifiedCredentialExpert';
const credentialType = ['VerifiedCredentialExpert'];
In my next blog, we will be changing these to point to our own VC definitions. We will also look at how the app is signing the issuance request. For now, let's have a look at the manifest. You can download the manifest by entering the credential URL into a browser.
You can see the display characteristic of the card, including the text, logo and background colour. The claims in the display section are the names used in the Authenticator UI. The Input section declares the attestations are to be taken from a B2C directory. The B2C endpoints and other pertinent data are available through the well-known discovery endpoint (.well-known/openid-configuration). The claims that will be required from the ID Token are also declared. These will be mapped to the VC claims (credentials).
So that you can easily see the issuance request. Use Ctrl+C in the terminal to stop issuer/app.js running. Open issuer/app.js in the editor and after the following line of code:
I have deliberately not specified the line number as the code may change. If you are typing the code yourself note that the glyph used between the parenthesis is a back-tick (`) and not a single quote mark. Save the file and restart the app.
In Authenticator, deactivate and then delete the VC. Go through the process of reissuing the VC and examine the terminal in VS Code.
The app logs the issuance request to the console prefixing it with https://jwt.ms/#id_token=
Ctrl+click the logged data, and it will open https://jwt.ms and display and decodes the issuance request, which is in the form of a JSON Web Token (JWT).
The JWT consists of three parts, each part separated by '.', header, body and signature. Both the header and body are included for signing.
The header identifies the DID of the signer. You can see the DID under the Key Identifier (kid) attribute in the header.
You will see that the request body includes the issuer's (iss) DID, the requested VC type and manifest URL.
If you look at the kid and iss DID values, you will see that they are the same. The #sig_24bb3074 appended to the kid is not part of the DID. As the DIDs are the same, it means that the issuer of the request signed the request. Issuer/app.js uses the VC SDK to build and sign the request (more in the next blog).
Copy the full DID (include did:ion:) from the iss attribute, and go to https://identity.foundation/ion/explorer/. Paste the DID into the search field. Click search, and it will show you that it is a published DID on ION.
Click Linked Domain, and you will see that the DID is linked to the https://did.woodgrovedemo.com/. This is the domain reported as verified by the Authenticator. If you want to retrieve the document that shows the linked DIDs go to https://did.woodgrovedemo.com/.well-known/did-configuration.json
Once the issuance request has been retrieved, the app has completed its task. It is now down to the Authenticator to complete the issuance cycle.
My background is in engineering, and I like to really understand what's going on under the hood. This knowledge helps me make really informed decisions in my role as an Identity Architect. I set up Fiddler as a remote proxy and proxied all my phone's traffic through Fiddler. In this way, I could capture all of the interactions between the authenticator app, issuer/app.js, the Azure AD VC service and more…
In this section, I am going to report the results of my Fiddler tracing. I will not go into every detail, but I will give you the big picture and point out the salient interactions. If you want the full details, set up a Fiddler proxy and start investigating.
As previously discussed, the Authenticator retrieves the issuance request.
I am not showing the return flows when a request is made for a specific item. For example, Get issuance requests assumes it is returned, hence, the double-headed arrow.
After the request has been retrieved, there is no further interaction with the user's browser or issuer/app.js. I have omitted these from the ongoing diagrams.
The issuance request may include the issuer's short-form, or long-form DID. A short-form DID consists of just the ION identifier, for example: did:ion:EiAUeAySrc1qgPucLYI_ytfudT8bFxUETNolzz4PCdy1bw, and it can be used when the DID has been published on ION to retrieve the DID document.
Long-form DIDs are also called private DIDs and are private to a subject. These may not have been published. Consequently, a long-form DID includes the DID document: did:ion:EiAUeAySrc1qgPucLYI_ytfudT8bFxUETNolzz4PCdy1bw:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpb24iOiJyZXBsYWNlIiwiZG9jdW1lbnQiOnsicHVibGljS2V5cyI6W3siaWQiOiJzaWdfMjRiYjMwNz……
The Authenticator contacts the DID resolver service and gets back the DID document. It can now verify the signature and check the DNS binding, which verifies the DID belongs to a specific DNS domain. If it cannot validate the DNS binding, you will see a warning that the app or website may be risky.
The next step is for the Authenticator is to request the manifest details from the Issuer service in Azure AD. You will remember that the manifest specifies how the card should be displayed, the required credentials and the method for obtaining the credentials. In this example, the input method is via an ID Token obtained by the user signing into a B2C directory.
The manifest details are returned as part of a signed JWT. The issuer, identified in the token, is the Azure AD VC service, and the JWT is signed by the service. As before, the signing DID is resolved, and the DNS bindings validated. I have left these the detail off last flow diagram for simplicity.
The IdP configuration document is obtained from the …/.well-known/openid-configuration endpoint on the B2C service. The Authenticator then uses an Authorization Code Flow with PKCE to get an ID Token. During this process, the user will be required to sign in. On my diagram, I have simply shown the flow as "Get IDToken". If you want to understand all details of the flows, including PKCE, please come to my identity masterclass.
The next step is for the Authenticator to send the ID Token to the Azure AD VC service. The service uses the claims in the ID Token to create the required verifiable credentials and return the VCs to the Authenticator.
When the Authenticator sends the ID Token to the VC service, it wraps it in a self-issued ID Token.
The previous figure shows the pertinent information. The Authenticator generates a new DID for the subject (user). The DID is added to the self-issued token, the audience (aud) identifies the token is for the VC Service, the contract defines the type of VC to be created, and the attestations claim includes the ID Token retrieved from the B2C IdP. The VC service can now generate a VC based on the information in the presented token.
The newly minted VC is returned as a JWT to the Authenticator:
Once again, I have simplified the diagram and just included the pertinent details. You will see that the Authenticator now holds a signed VC, including the subject DID and the appropriate credentials. Taking the example from my first blog, it's the digital equivalent of our real-world driving licence.
I will cover the three URL endpoints in the issued VC when we encounter them being used.
We now have two members of our trio, Issuer and Holder, but how does a verifier operate? Read on.
Running the Verifier App
Open VS Code and using File | open Folder, open the verifier folder:
In the terminal window, check you are in the version1\....\verifier folder and run:
While the environment is being built, you will see some warning messages which you can ignore.
In the terminal window, run the verifier app using:
You will notice in the VS Code console window it reports: "Example app listening on port 8082!".
In a separate command window, switch to the c:\ngrok directory and execute.
ngrok http 8082
Use your browser (not your mobile) to connect to the HTTPS endpoint.
You will see:
Click on Verify credentials, and a QR code is shown. The Microsoft Authenticator app is used to scan the QR code. This app has similar behaviour to the issuing app. When you click the button, a presentation request is generated and signed by the verifier application, a link is passed back to the browser and displayed as a QRCode.
The presentation request defines the VC/c