walt.id Identity
Overview
walt.id Identity is an open-source platform for decentralized identity and verifiable credentials. It gives you the building blocks to issue, hold and verify W3C Verifiable Credentials using open standards, including OpenID for Verifiable Credential Issuance (OID4VCI), OpenID for Verifiable Presentations (OID4VP) and Decentralized Identifiers (DIDs).
This SecureAnyCloud image runs walt.id Identity 0.22.0 on Ubuntu 24.04 LTS. It ships the three core backend services of the stack. Each runs as its pinned upstream container (by immutable digest) under a systemd service that starts it on boot and restarts it on failure.
What you get:
- The Issuer API on port 7002, which issues Verifiable Credentials to wallets over OID4VCI
- The Verifier API on port 7003, which requests and verifies Verifiable Presentations over OID4VP and runs configurable credential and presentation policies
- The Wallet API on port 7001, a server-side holder wallet that can receive, store and present credentials, backed by a local SQLite database
- walt.id Identity 0.22.0 from the official
waltid/issuer-api,waltid/verifier-apiandwaltid/wallet-apiimages, pinned by digest and run by systemd - The Issuer API and Verifier API served on
:7002and:7003 - The Wallet API on
:7001, bound to loopback so the credential store is not exposed to the internet by default - A per-VM wallet administrator account and per-VM wallet signing keys, generated on first boot and recorded in a root-only file
- A built-in end-to-end self-test that issues, holds and verifies a real credential
docker.service,waltid-issuer.service,waltid-verifier.serviceandwaltid-wallet.serviceas systemd units, enabled and active- No administrator baked into the image, and 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size. Choose a larger size for heavier use.
In the network security group (NSG), allow inbound 22/tcp from your management network, and 7002/tcp and 7003/tcp for the Issuer and Verifier APIs. The Wallet API on 7001 is bound to loopback and is not exposed.
The services speak plain HTTP. For production, front them with your own domain and TLS, and set the service base URLs accordingly (see the final step).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for walt.id Identity by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22), 7002 and 7003.
Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:waltid-identity-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name waltid-identity \
--image sac1647283583153:waltid-identity-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name waltid-identity --port 7002 --priority 1010
az vm open-port --resource-group <your-rg> --name waltid-identity --port 7003 --priority 1020Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
The stack runs as four systemd services: docker, waltid-issuer, waltid-verifier and waltid-wallet. Confirm that they are active. Also confirm that the Issuer and Verifier listen on their public ports while the Wallet stays on loopback:
systemctl is-active docker waltid-issuer waltid-verifier waltid-wallet
sudo ss -tlnp | grep -E ':7001|:7002|:7003' | awk '{print $4}' | sort -uExpected output:
active active active active 127.0.0.1:7001 *:7002 *:7003Step 5 - Retrieve your per-VM wallet credentials
The image ships with no administrator. On the first boot of every VM, waltid-firstboot.service generates a unique wallet administrator account and unique wallet signing keys, and records them in a root-only file. Confirm that first boot completed, then read the file:
systemctl is-active waltid-firstboot.service
sudo stat -c '%n mode=%a owner=%U:%G' /root/waltid-credentials.txt
sudo cat /root/waltid-credentials.txtThe file contains WALLET_ADMIN_EMAIL, WALLET_ADMIN_PASSWORD, and the Issuer, Verifier and Wallet API URLs. Keep the password safe, because it is unique to this VM.
Step 6 - Run the built-in end-to-end self-test
The image includes a self-test that exercises the whole platform. It issues a Verifiable Credential from the Issuer API and has the Wallet API claim it. It then asks the Verifier API for a presentation, has the Wallet present the credential, and confirms that the Verifier reports the presentation as valid. Run it:
sudo /usr/local/sbin/waltid-selftest.shThe expected final line is:
SELFTEST_OK issue->hold->verify verified=trueStep 7 - Issue a Verifiable Credential with the Issuer API
The Issuer API issues credentials over OID4VCI. This example creates a fresh issuer key and DID with the onboarding endpoint, then issues an OpenBadge credential. The response is an openid-credential-offer URL that a wallet can claim:
ISSUER=http://127.0.0.1:7002
ONB=$(curl -s -X POST "$ISSUER/onboard/issuer" -H 'Content-Type: application/json' \
-d '{"key":{"backend":"jwk","keyType":"secp256r1"},"did":{"method":"jwk"}}')
IKEY=$(echo "$ONB" | jq -c '.issuerKey');
IDID=$(echo "$ONB" | jq -r '.issuerDid')
curl -s -X POST "$ISSUER/openid4vc/jwt/issue" -H 'Content-Type: application/json' \
-d "$(jq -n --argjson ik "$IKEY" --arg did "$IDID" '{ issuerKey:$ik, issuerDid:$did, credentialConfigurationId:"OpenBadgeCredential_jwt_vc_json", credentialData:{"@context":["https://www.w3.org/2018/credentials/v1"],type:["VerifiableCredential","OpenBadgeCredential"],name:"Example badge",credentialSubject:{type:["AchievementSubject"]}}, mapping:{id:"<uuid>",issuer:{id:"<issuerDid>"},credentialSubject:{id:"<subjectDid>"},issuanceDate:"<timestamp>",expirationDate:"<timestamp-in:365d>"}, authenticationMethod:"PRE_AUTHORIZED"}')"; echoExpected output, an offer URL that a wallet can claim:
openid-credential-offer://?credential_offer_uri=http%3A%2F%2F<vm-ip>%3A7002%2Fdraft13%2FcredentialOffer%3Fid%3D...Step 8 - Verify a presentation with the Verifier API
The Verifier API creates a presentation request over OID4VP and runs policies against the presentation. Create a request for an OpenBadge credential:
VERIFIER=http://127.0.0.1:7003 curl -s -X POST "$VERIFIER/openid4vc/verify" -H 'Content-Type: application/json' -H 'responseMode: direct_post' \
-d '{"request_credentials":[{"format":"jwt_vc_json","type":"OpenBadgeCredential"}]}'; echoThe response is an openid4vp://authorize URL that a wallet resolves and answers. The verification result for the session is available at GET /openid4vc/session/<state>. The self-test in Step 6 runs this whole exchange automatically.
Step 9 - Use the Wallet API
The Wallet API is a server-side holder wallet. It is bound to loopback, so the credential store is not exposed. Reach it on the VM, or from your workstation over an SSH tunnel:
ssh -L 7001:127.0.0.1:7001 azureuser@<vm-public-ip>
# then open http://127.0.0.1:7001/swagger and log in with the
# WALLET_ADMIN_EMAIL / WALLET_ADMIN_PASSWORD from Step 5Step 10 - Production hardening
The Issuer and Verifier serve plain HTTP and embed their own base URL into credential offers and presentation requests, so relying wallets must be able to reach that address. For production:
- Put the Issuer and Verifier behind your own reverse proxy with TLS and a real domain name.
- Set the base URLs to your public HTTPS host. Edit
baseUrlin/etc/waltid/issuer/config/issuer-service.confand/etc/waltid/verifier/config/verifier-service.conf, then runsudo systemctl restart waltid-issuer waltid-verifier. - Restrict the NSG so that only the hosts that need the Issuer and Verifier can reach
7002and7003. - Keep the Wallet API on loopback, or expose it only through an authenticated gateway.
The base image is fully patched at build time and has unattended security upgrades enabled, so the OS keeps receiving security updates. For help, contact 24/7 SecureAnyCloud support.
Deploy on Azure
Launch walt.id Identity on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
walt.id Identity is an open-source platform for decentralized identity and verifiable credentials. It gives you the building blocks to issue, hold and verify W3C Verifiable Credentials using open standards, including OpenID for Verifiable Credential Issuance (OID4VCI), OpenID for Verifiable Presentations (OID4VP) and Decentralized Identifiers (DIDs).
This SecureAnyCloud image deploys walt.id Identity 0.22.0 from the pinned upstream container images. A systemd service manages each container, starting it on boot and restarting it on failure.
What you get:
- The Issuer API on port 7002, which issues Verifiable Credentials to wallets over OID4VCI
- The Verifier API on port 7003, which requests and verifies Verifiable Presentations over OID4VP and runs configurable credential and presentation policies
- The Wallet API on port 7001 (bound to loopback), a server-side holder wallet that can receive, store and present credentials, backed by a local SQLite database
- The web wallet, a browser user interface served on port 80 through an nginx reverse proxy, for registering, holding and presenting credentials
- A dedicated, independently resizable EBS data volume mounted at /var/lib/waltid that holds the Wallet API state (holder accounts, keys and stored credentials), so your data survives instance replacement
- Unique wallet signing and encryption keys and a unique wallet administrator account, created by a one-shot service on the first boot of every instance and written to
/root/waltid-credentials.txtwith mode 0600, so only the root user can read it - No administrator, no shared secret and no default credential in the image
Prerequisites
Before you deploy this image, you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network, port 80 for the web wallet, and ports 7002 and 7003 if you will call the Issuer and Verifier APIs from your own applications
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for walt.id Identity. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger. walt.id Identity runs three JVM API services plus the web wallet, so it needs the memory. Choose your EC2 key pair under Key pair (login).
Under Network settings, select your VPC and subnet. Create or select a security group that opens port 22 from your management network, port 80 for the web wallet, and ports 7002 and 7003 for the Issuer and Verifier APIs. Leave the root volume at the default size or larger.
Select Launch instance. First-boot initialization generates the per-instance wallet keys and administrator account. On a fresh instance this takes a minute or two after the instance state becomes Running and the status checks pass.
Launch the instance from the AWS CLI
The following command launches an instance from the SecureAnyCloud walt.id Identity Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, and <subnet-id> with your subnet ID. Replace <security-group-id> with a security group that opens ports 22, 80, 7002 and 7003 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=waltid-identity}]'When the instance reaches the Running state and its status checks pass, note its public IP address or DNS name. You can find them in the EC2 console or with aws ec2 describe-instances.
Connect to your instance
Connect over SSH using your key pair and the login user for your operating system variant.
OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/your-key.pem ubuntu@<public-ip>Retrieve the wallet administrator credentials
On the first boot of your instance, the image generates a unique wallet administrator account and unique wallet signing keys. Retrieve them with:
sudo cat /root/waltid-credentials.txtThe file lists the wallet administrator email (waltid-admin@localhost) and password, and the Issuer, Verifier and Wallet API URLs. Store the password somewhere safe. It is unique to this instance.
Open the web wallet
Browse to http://<public-ip>/ to open the web wallet, which nginx serves on port 80. Sign in with the wallet administrator email and password from the credentials file, or choose Sign up here to register a new holder account.
After you sign in, you land on the credentials view, which lists the Verifiable Credentials held by the wallet. Use Receive to claim a credential from an issuer and Present to share one with a verifier.
Select a credential to see its detail: the issuer Decentralized Identifier, the validity period and the raw credential JSON.
Verify the services are running
Confirm that the platform services are active and answering on the instance:
systemctl is-active docker waltid-issuer waltid-verifier waltid-wallet waltid-demo-wallet nginx echo "web wallet: $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/)" echo "issuer api: $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:7002/swagger/index.html)" echo "verifier api:$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:7003/swagger/index.html)"Each service should report active and each endpoint should return 200.
Issue, hold and verify a credential (built-in self-test)
The image ships an end-to-end self-test that exercises the whole flow using only the on-box APIs. It creates an issuer key and issues an OpenBadge Verifiable Credential. The wallet claims the credential, the verifier requests a presentation, and the wallet presents it. The test then asserts that the verifier reports the presentation as verified.
sudo /usr/local/sbin/waltid-selftest.shA successful run prints SELFTEST_OK issue->hold->verify verified=true.
Use the Issuer and Verifier APIs
The Issuer API (port 7002) and Verifier API (port 7003) expose interactive OpenAPI documentation at the /swagger path. Open http://<public-ip>:7002/swagger and http://<public-ip>:7003/swagger in a browser to explore the endpoints. You can also integrate the APIs into your own applications to issue and verify W3C Verifiable Credentials over OID4VC.
The Issuer and Verifier learn the instance public address on every boot and embed it into the credential offers and presentation requests they produce. Offers and requests therefore point at the right host with no hand editing.
The Wallet API is bound to loopback. Reach it through the web wallet on port 80, from the instance itself, or over an SSH tunnel:
ssh -i /path/to/your-key.pem -L 7001:127.0.0.1:7001 ubuntu@<public-ip>With the tunnel open, browse to http://127.0.0.1:7001/swagger on your workstation.
The dedicated data volume
The Wallet API state (the holder accounts, keys and stored credentials) lives on a dedicated EBS data volume mounted at /var/lib/waltid. The volume is separate from the operating system disk, so it survives instance replacement and can be resized independently. Check the mount:
df -h /var/lib/waltidTo grow the wallet data volume, expand the EBS volume in the AWS console. Then extend the filesystem on the instance with sudo resize2fs on the mounted device.
Production hardening with your own DNS and TLS
For production, front the services with your own domain name and TLS. Point a DNS record at the instance. Terminate HTTPS at nginx (or an AWS load balancer) with a certificate for your domain. Restrict the Issuer and Verifier security group rules to the networks that need them.
The Issuer and Verifier derive their public base URL from the instance address on each boot. Once you place them behind a stable hostname, set the base URLs explicitly to your domain in /etc/waltid/issuer/config/issuer-service.conf and /etc/waltid/verifier/config/verifier-service.conf. Then restart the two services.
Support
SecureAnyCloud maintains this image and provides 24/7 technical support by email and chat. We can help with deployment, the Issuer, Verifier and Wallet APIs, OID4VC and DID configuration, credential and presentation policies, the web wallet, TLS and runtime tuning.
walt.id Identity is licensed under the Apache License 2.0. The SecureAnyCloud charge covers packaging, security patching, image maintenance and support.
Deploy on AWS
Launch walt.id Identity on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com