Build your own apps based on our implementation

Warning and Disclaimer

We recommend not to use the current Digital ID Library in production. See the roadmap for more information.


Since this is currently only a test version, you need Apache Maven to build the library from the source code. For compilation, JDK 8 or newer is required.



The Digital ID Library is structured in such a way that clients and servers share as much code as possible:

Project Dependencies


The current versions of these projects are:


Clone the maven, utility, database and core projects from GitHub:

git clone
git clone
git clone
git clone


Build the source code as follows (and in that order):

cd digitalid-maven
mvn clean install
cd ../digitalid-utility
mvn clean install
cd ../digitalid-database
mvn clean install
cd ../digitalid-core
mvn clean install
cd ..


If you only want to include the utility project for the benefits described in the design section, you can add the following dependency to your POM to load it from the Maven Repository:


As soon as the other projects are also more mature, we are going to publish them in the Maven Repository as well.



If you want to build a client, add the following dependencies to your POM after having compiled the sources:



Various configurations need to be initialized before the library can be used:

import net.digitalid.utility.configuration.Configuration;



Before we can create an identity, we first have to create the client with which we will manage the identity:

import net.digitalid.core.client.Client;
import net.digitalid.core.client.ClientBuilder;
import net.digitalid.core.permissions.ReadOnlyAgentPermissions;

final @Nonnull Client client = ClientBuilder.withIdentifier("").withDisplayName("Company App").withPreferredPermissions(ReadOnlyAgentPermissions.GENERAL_WRITE).build();


The following code checks whether a string is a valid identifier and whether such an identity already exists:

import net.digitalid.core.identification.identifier.InternalNonHostIdentifier;

final @Nonnull String string = "";
if (InternalNonHostIdentifier.isValid(string)) {
    final @Nonnull InternalNonHostIdentifier identifier = InternalNonHostIdentifier.with(userString);
    if (!identifier.exists()) {
        // There exists no identity with this identifier and thus a new account can be opened


All actions and queries are performed on roles. You can create a new identity with:

import net.digitalid.core.account.OpenAccount;
import net.digitalid.core.client.role.NativeRole;
import net.digitalid.core.identification.identity.Category;

final @Nonnull NativeRole role = OpenAccount.of(Category.NATURAL_PERSON, identifier, client);


Once you have such a role, it is easy to retrieve an attribute of that role:

import net.digitalid.core.attribute.Attribute;
import net.digitalid.core.attribute.AttributeTypes;

final @Nonnull Attribute attribute = Attribute.of(role, AttributeTypes.NAME);

Until we provide better utility methods, setting the value of an attribute is a bit inconvenient:

import net.digitalid.core.pack.Pack;
import net.digitalid.core.pack.PackConverter;
import net.digitalid.core.signature.Signature;
import net.digitalid.core.signature.SignatureBuilder;
import net.digitalid.core.signature.attribute.AttributeValue;
import net.digitalid.core.signature.attribute.UncertifiedAttributeValue;

final @Nonnull Signature<Pack> signature = SignatureBuilder.withObjectConverter(PackConverter.INSTANCE).withObject(Pack.pack(StringConverter.INSTANCE, "My Name", AttributeTypes.NAME)).withSubject(identifier).build();
final @Nonnull AttributeValue value = UncertifiedAttributeValue.with(signature);

Setting the (in this example public) visibility of the attribute is then straightforward:

import net.digitalid.core.expression.PassiveExpression;
import net.digitalid.core.expression.PassiveExpressionBuilder;

final @Nonnull PassiveExpression visibility = PassiveExpressionBuilder.withEntity(role).withString("everybody").build();


The attributes of other identities are cached locally and can be retrieved as follows:

import net.digitalid.core.cache.CacheQueryBuilder;

final @Nonnull InternalNonHostIdentifier friend = new InternalNonHostIdentifier("");
final @Nonnull String name = CacheQueryBuilder.withConverter(StringConverter.INSTANCE).withRequestee(friend.resolve()).withRequester(role).withType(AttributeTypes.NAME).build().execute();


Java Ecosystem

We used the programming language Java for the Digital ID Library due to its wide adoption and the maturity of its ecosystem.

Code Generation

The biggest downside of Java is that you have to write a lot of boilerplate code. We managed to reduce this overhead to a minimum by heavily using Java Annotation Processing to automatically generate builders, subclasses, converters and initializers.

For example,

import net.digitalid.utility.annotations.method.Impure;
import net.digitalid.utility.annotations.method.Pure;
import net.digitalid.utility.generator.annotations.generators.GenerateBuilder;
import net.digitalid.utility.generator.annotations.generators.GenerateSubclass;
import net.digitalid.utility.rootclass.RootClass;

public abstract class MutableClass extends RootClass {
    public abstract int getValue();
    public abstract void setValue(int value);

generates the subclass (slightly edited here for conciseness)

import java.util.Objects;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.digitalid.utility.annotations.method.Pure;

class MutableClassSubclass extends MutableClass {
    private int value;
    public int getValue() {
        return this.value;
    public void setValue(int value) {
        this.value = value;
    MutableClassSubclass(int value) {
        this.value = value;
    public boolean equals(@Nullable Object object) {
        if (object == this) {
            return true;
        if (object == null || !(object instanceof MutableClass)) {
            return false;
        final @Nonnull MutableClass that = (MutableClass) object;
        boolean result = true;
        result = result && Objects.equals(this.getValue(), that.getValue());
        return result;
    public int hashCode() {
        int prime = 92_821;
        int result = 46_411;
        result = prime * result + Objects.hashCode(getValue());
        return result;
    public @Nonnull String toString() {
        return "MutableClass(value: " + getValue() + ")";

and the builder (edited here for conciseness)

import javax.annotation.Nonnull;

import net.digitalid.utility.annotations.method.Impure;
import net.digitalid.utility.annotations.method.Pure;

public class MutableClassBuilder {
    public static class InnerMutableClassBuilder {
        private InnerMutableClassBuilder() {}
        private int value = 0;
        public @Nonnull InnerMutableClassBuilder withValue(int value) {
            this.value = value;
            return this;
        public @Nonnull MutableClass build() {
            return new MutableClassSubclass(value);
    public static @Nonnull InnerMutableClassBuilder withValue(int value) {
        return new InnerMutableClassBuilder().withValue(value);

Static Constructors

When we cannot or do not want to generate a builder automatically, we use static methods like of(…) and with(…) instead of public constructors.

This design principle has the following advantages:

  • Possibility to return a cached object instead of a new one, which is important for the observer pattern.
  • Possibility to return null instead of a new object, which is useful to propagate null values.
  • Possibility to perform operations before having to call the constructor of the superclass.
  • Possibility to choose a more descriptive name for the static constructor method.
  • Possibility to construct objects of a subclass instead of the current class.
  • Possibility to make use of these possibilities at some later point in time.
  • And NetBeans correctly checks non-null parameter assignments.

Besides slightly bigger classes, the biggest disadvantage seems to be that static methods are inherited and can thus lead to namespace pollution.

Design by Contract

We follow the design by contract methodology. When you annotate method parameters and return types, the subclass generator generates a subclass that overrides the method and performs the corresponding checks.

For example,

import net.digitalid.utility.annotations.method.Impure;
import net.digitalid.utility.generator.annotations.generators.GenerateSubclass;
import net.digitalid.utility.validation.annotations.math.Positive;

public abstract class Test {
    public void setValue(@Positive int value) { /* … */}

generates the subclass

import net.digitalid.utility.contracts.Require;
import net.digitalid.utility.validation.annotations.math.Positive;

class TestSubclass extends Test {
    public void setValue(@Positive int value) {
        Require.that(value > 0).orThrow("The value has to be positive but was $.", value);

Type Safety

A built-in form of design by contract is the type safety provided by Java. We tried to use class hierarchies wherever possible instead of relying on annotations to restrict a method parameter or a return type. The downside is that it makes class hierarchies more complex.


Production (v0.7)

  • Auto-incrementing columns
  • Contact management
  • Credential issuance
  • Agent authorization
  • Better test coverage
  • Security review

Self-Hosting (v0.8)

  • Action pusher
  • Audit functionality
  • Domain verification
  • Certificate issuance
  • Client synchronization

Functionality (v0.9)

  • Hierarchical contexts
  • Offline functionality
  • Identity relocation
  • Restricted agents


There has been an older, Apache Ant-based version of this library. A lot of things have changed and improved since then. Some artifacts still need to be rewritten, though (see core).


Please file any issues you encounter directly in the corresponding GitHub project (utility, database or core). If you are uncertain to which project an issue belongs, use the last one or contact us directly. When you do so, please attach the current log file. (Since the log file might contain sensitive information, it might be a good idea to first have a look at it yourself.)


The code of the Digital ID Library is available under the Apache License 2.0, which is a permissive software license that lets you do anything you want with the code as long as you provide proper attribution and don’t hold us liable.


The following graphics depict how the artifacts of each project depend on each other. If you only need certain functionality, you can depend on the corresponding artifact directly.


Utility Dependencies


Database Dependencies


Core Dependencies

Please note that the artifacts with the red border largely still have to be written.