LinkedDataHub uses WebID as the Single sign-on (SSO)
- protocol for distributed applications, which is based on authentication using TLS client certficates. Using WebID, you will be able to authenticate with every LinkedDataHub application.
- Read more about WebID.
-
There are two ways to get a LinkedDataHub WebID: setup and signup.
Complete the setup and run own an instance of LinkedDataHub.
-
The ssl/owner/keystore.p12 file is your WebID certificate. The password is the owner_cert_password Docker secret value.
-
-
-
Sign up to an existing instance of LinkedDataHub. Click the Sign up button and fill out the form with your
- details to get a WebID, as shown below.
-
-
-
-
You will get an email with a .p12 file attached, which is your WebID certificate. The certificate's password is the one you entered in the signup form.
Unlike most LinkedDataHub resources, your WebID profile will have public access as required by the protocol. Your email address will be hidden however.
-
-
-
-
Install certificate
-
The final step is to install the client certificate into your web browser. It is done by importing the .p12
- file using the browser's certificate manager and providing the password that you supplied during signup. The
- manager dialog can be opened following the steps below, depending on which browser you use:
The file is installed directly into the operating system. Open the file and import it using the
- Keychain Access
- tool. Drag the .p12 file to the login section.
-
Microsoft Edge
-
Does not support certificate management, you need to install the file into Windows.
- Read more here.
-
-
You need to install the certificate on all devices/browsers that you are using to access LinkedDataHub.
+
+
Get certificate
+
LinkedDataHub uses WebID as the Single sign-on (SSO)
+ protocol for distributed applications, which is based on authentication using TLS client certficates. Using WebID, you will be able to authenticate with every LinkedDataHub application.
+ Read more about WebID.
+
There are two ways to get a LinkedDataHub WebID: setup and signup.
Complete the setup and run own an instance of LinkedDataHub.
+
The ssl/owner/keystore.p12 file is your WebID certificate. The password is the owner_cert_password Docker secret value.
-
-
Log in
-
Open the URL of the LinkedDataHub instance in the web browser (that you installed the WebID certificate into). Using a local setup, it runs on https://localhost:4443/ by default.
-
With the certificate installed, there is no login procedure — you are automatically authenticated on all
- LinkedDataHub applications. This is known as Single sign-on (SSO).
-
Applications can provide public access to some or all documents, meaning you can freely browse their public resources
- and perform actions that are allowed for public access. In order to access protected (non-public) resources, as well
- as to access administration application, users have to be authenticated as well authorized (authorizations
- can be requested).
-
-
Authenticated agents are not guaranteed to have access to all resources. Different access levels for
- different agents can be specified by the application administrators.
-
+
+
Sign up to an existing instance of LinkedDataHub. Click the Sign up button and fill out the form with your
+ details to get a WebID, as shown below.
+
+
+
+
You will get an email with a .p12 file attached, which is your WebID certificate. The certificate's password is the one you entered in the signup form.
-
-
-
Click the Login with Google button in the navbar to authenticate with your Google account.
-
If the email address of your Google account matches the dataspace owner's email address that was specified during setup, you will be authenticated as the owner with full control access rights.
Unlike most LinkedDataHub resources, your WebID profile will have public access as required by the protocol. Your email address will be hidden however.
+
+
+
+
Install certificate
+
The final step is to install the client certificate into your web browser. It is done by importing the .p12
+ file using the browser's certificate manager and providing the password that you supplied during signup. The
+ manager dialog can be opened following the steps below, depending on which browser you use:
The file is installed directly into the operating system. Open the file and import it using the
+ Keychain Access
+ tool. Drag the .p12 file to the login section.
+
Microsoft Edge
+
Does not support certificate management, you need to install the file into Windows.
+ Read more here.
+
+
You need to install the certificate on all devices/browsers that you are using to access LinkedDataHub.
+
+
+
Log in
+
Open the URL of the LinkedDataHub instance in the web browser (that you installed the WebID certificate into). Using a local setup, it runs on https://localhost:4443/ by default.
+
With the certificate installed, there is no login procedure — you are automatically authenticated on all
+ LinkedDataHub applications. This is known as Single sign-on (SSO).
+
Applications can provide public access to some or all documents, meaning you can freely browse their public resources
+ and perform actions that are allowed for public access. In order to access protected (non-public) resources, as well
+ as to access administration application, users have to be authenticated as well authorized (authorizations
+ can be requested).
+
+
Authenticated agents are not guaranteed to have access to all resources. Different access levels for
+ different agents can be specified by the application administrators.
+
+
+
+
+
Click the Login with Google button in the navbar to authenticate with your Google account.
+
If the email address of your Google account matches the dataspace owner's email address that was specified during setup, you will be authenticated as the owner with full control access rights.
To sign in, click on the Login with Google button. A unique agent URI will be assigned to you and used to authenticate you with the applications on the platform.
This section assumes you will be running on your local machine, i.e. localhost. If you intend to run it on a different host, change the system base URI.
-
Prerequisites:
-
-
bash shell. It should be included by default on Linux. On Windows you can install the Windows Subsystem for Linux.
Fork the LinkedDataHub repository
- and clone the fork into a folder
-
In the folder, create an .env file and fill out the missing values (you can use .env_sample as a template). For example:
-
COMPOSE_CONVERT_WINDOWS_PATHS=1
+
Start LinkedDataHub
+
This section assumes you will be running on your local machine, i.e. localhost. If you intend to run it on a different host, change the system base URI.
+
Prerequisites:
+
+
bash shell. It should be included by default on Linux. On Windows you can install the Windows Subsystem for Linux.
Setup the server's SSL certificates by running this from command line:
-
./bin/server-cert-gen.sh .env nginx ssl
- The script will create an ssl/server sub-folder where the SSL certificate will be stored.
-
-
Create the following secrets with certificate/truststore passwords:
-
-
secrets/client_truststore_password.txt
-
secrets/owner_cert_password.txt
-
secrets/secretary_cert_password.txt
-
- The one you will need to remember in order to authenticate with LinkedDataHub using WebID client certificate is owner_cert_password.
-
-
(Optional) If you need to configure Bearer token authentication for SPARQL services, create secrets/credentials.trig with your service credentials. See the configuration reference for details.
-
Run this from command line:
-
docker-compose up --build
- LinkedDataHub will start and mount the following sub-folders:
-
-
data where the backend triplestores will persist RDF data
-
datasets where the owner and secretary agent metadata is persisted
-
ssl/owner and ssl/secretary where the owner and secretary SSL certificates and WebID public keys are persisted
-
uploads where LinkedDataHub stores content-hashed file uploads
You are now the owner of this LinkedDataHub instance; ssl/owner/keystore.p12 is your WebID certificate. Password is the owner_cert_password secret value.
-
After a successful startup you should see periodic healthcheck requests being made to the https://localhost:4443/ns URL.
-
-
-
Reset
-
If you need to start fresh and wipe the existing setup, you can do that using:
-
sudo rm -rf data datasets uploads ssl && docker-compose down -v
-
-
This will remove persisted RDF data, SSL keys, and uploaded files as well as the Docker volumes.
LinkedDataHub Cloud is a managed LinkedDataHub service, meaning that you do not have to do any setup yourself.
-
Proceed to get an account to see how to login to LinkedDataHub Cloud.
-
-
+
+
Setup the server's SSL certificates by running this from command line:
+
./bin/server-cert-gen.sh .env nginx ssl
+ The script will create an ssl/server sub-folder where the SSL certificate will be stored.
+
+
Create the following secrets with certificate/truststore passwords:
+
+
secrets/client_truststore_password.txt
+
secrets/owner_cert_password.txt
+
secrets/secretary_cert_password.txt
+
+ The one you will need to remember in order to authenticate with LinkedDataHub using WebID client certificate is owner_cert_password.
+
+
(Optional) If you need to configure Bearer token authentication for SPARQL services, create secrets/credentials.trig with your service credentials. See the configuration reference for details.
+
Run this from command line:
+
docker-compose up --build
+ LinkedDataHub will start and mount the following sub-folders:
+
+
data where the backend triplestores will persist RDF data
+
datasets where the owner and secretary agent metadata is persisted
+
ssl/owner and ssl/secretary where the owner and secretary SSL certificates and WebID public keys are persisted
+
uploads where LinkedDataHub stores content-hashed file uploads
You are now the owner of this LinkedDataHub instance; ssl/owner/keystore.p12 is your WebID certificate. Password is the owner_cert_password secret value.
+
After a successful startup you should see periodic healthcheck requests being made to the https://localhost:4443/ns URL.
+
+
+
Reset
+
If you need to start fresh and wipe the existing setup, you can do that using:
+
sudo rm -rf data datasets uploads ssl && docker-compose down -v
+
+
This will remove persisted RDF data, SSL keys, and uploaded files as well as the Docker volumes.
config/system.trig — Internal service wiring (app-to-service bindings, SPARQL endpoints)
-
secrets/credentials.trig — Service authentication credentials (optional, gitignored). See the authentication reference for details.
-
-
The configuration uses the Application domain ontology. A dataspace is comprised of an end-user
- application and an administrative application, both backed by their own SPARQL service. Each application can also specify its own XSLT stylesheet.
Application base URIs need to be relative to the system base URI configured in the .env file. A change of system base URI currently requires a change of application base URIs, otherwise they will not be reachable.
-
-
-
Create a dataspace
-
To create a new dataspace:
-
-
Add instances of lapp:EndUserApplication and lapp:AdminApplication to config/dataspaces.trig, following the default dataspace as a template
-
Add corresponding sd:Service instances to config/system.trig with the SPARQL endpoint connection details
-
-
The relationship between end-user and admin applications is automatically inferred based on naming conventions — you don't need to manually specify
- lapp:endUserApplication or lapp:adminApplication properties. Applications with base URIs containing admin/ are
- automatically recognized as administration applications.
-
-
Use URIs (for example in the urn: scheme) to identify apps and services, not blank nodes. Make sure both files' syntax is valid Turtle, otherwise the setup will not work. You can use Turtle Validator to check the syntax.
-
-
-
-
Change stylesheet
-
Change the value of ac:stylesheet to the URI of your XSLT stylesheet. Add the property if it is absent.
-
The stylesheet can either be uploaded as a file or mounted in docker-compose.yml, in the volumes section of the linkeddatahub service. Mounting is useful while developing.
-
You will need to restart LinkedDataHub's Docker service for the new stylesheet to take effect.
-
It is rarely necessary to change the stylesheet of an admin application.
-
-
-
-
Manage services
-
LinkedDataHub service as well as the default SPARQL services fuseki-end-user and fuseki-admin are defined in docker-compose.yml and run as Docker containers.
-
While LinkedDataHub uses Apache Jena Fuseki by default, you can configure it to use other SPARQL 1.1-compatible triplestores such as QLever, Tentris, or others.
-
See the triplestores reference for step-by-step configuration examples, including QLever setup and troubleshooting.
On the top left-hand side click on the Context button
-
In the form that opens, fill out the following fields:
-
-
Base URI
-
Here you can change the relative path of your context. It may not have forward slashes (/) in it. Attempt to use an already existing path will result in an error. By default, a unique UUID will be assigned.
-
Title
-
The human-readable title of your context
-
Description
-
Optionally, enter a human-readable description of your context
-
Public
-
Choose whether your context should be publicly listed on LinkedDataHub Cloud
-
-
-
-
The following video shows the creation of both a context and a dataspace:
In the form that opens, fill out the following fields:
-
-
Base URI
-
Here you can change the relative path of your context. It may not have forward slashes (/) in it. Attempt to use an already existing path will result in an error.
-
Title
-
The human-readable title of your context
-
Description
-
Optionally, enter a human-readable description of your context
-
Public
-
Choose whether your dataspace should be publicly listed on LinkedDataHub Cloud. This does not mean that the documents in the dataspace will be public — they are subject to access control.
-
-
-
-
The following video shows the creation of both a context and a dataspace:
The configuration uses the Application domain ontology. A dataspace is comprised of an end-user
+ application and an administrative application, both backed by their own SPARQL service. Each application can also specify its own XSLT stylesheet.
Application base URIs need to be relative to the system base URI configured in the .env file. A change of system base URI currently requires a change of application base URIs, otherwise they will not be reachable.
+
+
+
Create a dataspace
+
To create a new dataspace:
+
+
Add instances of lapp:EndUserApplication and lapp:AdminApplication to config/dataspaces.trig, following the default dataspace as a template
+
Add corresponding sd:Service instances to config/system.trig with the SPARQL endpoint connection details
+
+
The relationship between end-user and admin applications is automatically inferred based on naming conventions — you don't need to manually specify
+ lapp:endUserApplication or lapp:adminApplication properties. Applications with base URIs containing admin/ are
+ automatically recognized as administration applications.
+
+
Use URIs (for example in the urn: scheme) to identify apps and services, not blank nodes. Make sure both files' syntax is valid Turtle, otherwise the setup will not work. You can use Turtle Validator to check the syntax.
+
+
Change stylesheet
+
Change the value of ac:stylesheet to the URI of your XSLT stylesheet. Add the property if it is absent.
+
The stylesheet can either be uploaded as a file or mounted in docker-compose.yml, in the volumes section of the linkeddatahub service. Mounting is useful while developing.
+
You will need to restart LinkedDataHub's Docker service for the new stylesheet to take effect.
+
It is rarely necessary to change the stylesheet of an admin application.
+
+
+
+
Manage services
+
LinkedDataHub service as well as the default SPARQL services fuseki-end-user and fuseki-admin are defined in docker-compose.yml and run as Docker containers.
+
While LinkedDataHub uses Apache Jena Fuseki by default, you can configure it to use other SPARQL 1.1-compatible triplestores such as QLever, Tentris, or others.
+
See the triplestores reference for step-by-step configuration examples, including QLever setup and troubleshooting.
An RDF ontology file that imports the external vocabulary using owl:imports and attaches blocks to properties using ldh:view (forward relationships) or ldh:inverseView (inverse relationships). Blocks are typically ldh:View resources with SPARQL queries that render related data for property values.
layout.xsl — XSLT stylesheet
-
XSLT transformation file with templates that override default rendering using system modes like bs2:* (Bootstrap 2.3.2 components) and xhtml:* (XHTML elements). See Stylesheets reference for details on XSLT customization.
+
XSLT transformation file with templates that override default rendering using system modes like bs2:* (Bootstrap 2.3.2 components) and xhtml:* (XHTML elements). See Stylesheets reference for details on XSLT customization.
Package files are organized in the LinkedDataHub-Apps repository:
packages/
@@ -191,7 +191,7 @@ schema:knows ldh:view :PersonKnows .
ORDER BY ?person
\"\"\" .
Write XSLT stylesheet
-
Create layout.xsl with XSLT templates using system modes like bs2:* and xhtml:*. See the Stylesheets reference for template customization patterns.
+
Create layout.xsl with XSLT templates using system modes like bs2:* and xhtml:*. See the Stylesheets reference for template customization patterns.
"""^^rdf:XMLLiteral .
- # Category revenue chart
+ # Category revenue chart (wrapped in ldh:Object per ContentMode contract)
+ <#category-revenue-block> a ldh:Object ;
+ rdf:value <#category-revenue> .
+
<#category-revenue> a ldh:ResultSetChart ;
dct:title "Revenue by category" ;
spin:query <#category-revenue-query> ;
@@ -62,7 +65,10 @@ ORDER BY DESC(?revenue)""" .
Categories with more products may indicate core competencies or simply broader product lines.
"""^^rdf:XMLLiteral .
- # Products per category chart
+ # Products per category chart (wrapped in ldh:Object per ContentMode contract)
+ <#products-per-category-block> a ldh:Object ;
+ rdf:value <#products-per-category> .
+
<#products-per-category> a ldh:ResultSetChart ;
dct:title "Products per category" ;
spin:query <#products-per-category-query> ;
diff --git a/demo/northwind-traders/customers.ttl b/demo/northwind-traders/customers.ttl
index 05518c5..27e421f 100644
--- a/demo/northwind-traders/customers.ttl
+++ b/demo/northwind-traders/customers.ttl
@@ -10,9 +10,9 @@
<> a dh:Container ;
dct:title "Customers" ;
rdf:_1 <#customers-intro> ;
- rdf:_2 <#top-customers> ;
+ rdf:_2 <#top-customers-block> ;
rdf:_3 <#geographic-distribution> ;
- rdf:_4 <#customers-by-country> ;
+ rdf:_4 <#customers-by-country-block> ;
rdf:_5 <#customer-insights> ;
rdf:_6 <#select-customers> .
@@ -24,7 +24,10 @@
and market concentration helps prioritize account management and target growth strategies.
"""^^rdf:XMLLiteral .
- # Top customers chart
+ # Top customers chart (wrapped in ldh:Object per ContentMode contract)
+ <#top-customers-block> a ldh:Object ;
+ rdf:value <#top-customers> .
+
<#top-customers> a ldh:ResultSetChart ;
dct:title "Top 10 customers by revenue" ;
spin:query <#top-customers-query> ;
@@ -61,7 +64,10 @@ LIMIT 10""" .
Understanding geographic concentration helps guide expansion efforts and resource allocation.
"""^^rdf:XMLLiteral .
- # Customers by country chart
+ # Customers by country chart (wrapped in ldh:Object per ContentMode contract)
+ <#customers-by-country-block> a ldh:Object ;
+ rdf:value <#customers-by-country> .
+
<#customers-by-country> a ldh:ResultSetChart ;
dct:title "Customers by country" ;
spin:query <#customers-by-country-query> ;
diff --git a/demo/northwind-traders/employees.ttl b/demo/northwind-traders/employees.ttl
index 435baff..ec672cc 100644
--- a/demo/northwind-traders/employees.ttl
+++ b/demo/northwind-traders/employees.ttl
@@ -10,7 +10,7 @@
<> a dh:Container ;
dct:title "Employees" ;
rdf:_1 <#employee-intro> ;
- rdf:_2 <#sales-by-employee> ;
+ rdf:_2 <#sales-by-employee-block> ;
rdf:_3 <#select-employees> .
# Intro XHTML
@@ -21,7 +21,10 @@
contributions helps recognize top performers, identify coaching opportunities, and optimize territory assignments.
"""^^rdf:XMLLiteral .
- # Sales by employee chart
+ # Sales by employee chart (wrapped in ldh:Object per ContentMode contract)
+ <#sales-by-employee-block> a ldh:Object ;
+ rdf:value <#sales-by-employee> .
+
<#sales-by-employee> a ldh:ResultSetChart ;
dct:title "Sales by employee" ;
spin:query <#sales-by-employee-query> ;
diff --git a/demo/northwind-traders/install.sh b/demo/northwind-traders/install.sh
index 0d759ae..fa2b0a6 100755
--- a/demo/northwind-traders/install.sh
+++ b/demo/northwind-traders/install.sh
@@ -29,6 +29,8 @@ printf "\n### Importing namespace ontology\n\n"
./import-ns.sh "$base" "$cert_pem_file" "$cert_password" "$proxy"
+exit 1
+
cd ..
cd ..
diff --git a/demo/northwind-traders/orders.ttl b/demo/northwind-traders/orders.ttl
index 5fbd569..e9f32e5 100644
--- a/demo/northwind-traders/orders.ttl
+++ b/demo/northwind-traders/orders.ttl
@@ -10,11 +10,11 @@
<> a dh:Container ;
dct:title "Orders" ;
rdf:_1 <#orders-intro> ;
- rdf:_2 <#orders-over-time> ;
+ rdf:_2 <#orders-over-time-block> ;
rdf:_3 <#geographic-intro> ;
- rdf:_4 <#orders-by-country> ;
+ rdf:_4 <#orders-by-country-block> ;
rdf:_5 <#order-trends-summary> ;
- rdf:_6 <#sales-by-region-per-year> ;
+ rdf:_6 <#sales-by-region-per-year-block> ;
rdf:_7 <#select-orders> .
# Object block (references the view)
@@ -51,7 +51,10 @@
helps optimize inventory, predict demand, and identify growth opportunities across different markets.
"""^^rdf:XMLLiteral .
- # Orders over time chart
+ # Orders over time chart (wrapped in ldh:Object per ContentMode contract)
+ <#orders-over-time-block> a ldh:Object ;
+ rdf:value <#orders-over-time> .
+
<#orders-over-time> a ldh:ResultSetChart ;
dct:title "Orders per month" ;
spin:query <#orders-by-month-query> ;
@@ -82,7 +85,10 @@ ORDER BY ?month""" .
and helps identify expansion opportunities or regional challenges.
"""^^rdf:XMLLiteral .
- # Orders by country chart
+ # Orders by country chart (wrapped in ldh:Object per ContentMode contract)
+ <#orders-by-country-block> a ldh:Object ;
+ rdf:value <#orders-by-country> .
+
<#orders-by-country> a ldh:ResultSetChart ;
dct:title "Orders by country" ;
spin:query <#orders-by-country-query> ;
@@ -106,7 +112,10 @@ GROUP BY ?country
ORDER BY DESC(?orderCount)
LIMIT 10""" .
- # Chart block
+ # Chart block (wrapped in ldh:Object per ContentMode contract)
+ <#sales-by-region-per-year-block> a ldh:Object ;
+ rdf:value <#sales-by-region-per-year> .
+
<#sales-by-region-per-year> a ldh:ResultSetChart ;
dct:title "Sales by region per year" ;
spin:query <#sales-by-regions-by-year-query> ;
diff --git a/demo/northwind-traders/products.ttl b/demo/northwind-traders/products.ttl
index 9dba6a2..84ba577 100644
--- a/demo/northwind-traders/products.ttl
+++ b/demo/northwind-traders/products.ttl
@@ -10,10 +10,10 @@
<> a dh:Container ;
dct:title "Products" ;
rdf:_1 <#products-intro> ;
- rdf:_2 <#top-selling-products> ;
+ rdf:_2 <#top-selling-products-block> ;
rdf:_3 <#category-analysis-intro> ;
- rdf:_4 <#revenue-by-category> ;
- rdf:_5 <#products-by-supplier> ;
+ rdf:_4 <#revenue-by-category-block> ;
+ rdf:_5 <#products-by-supplier-block> ;
rdf:_6 <#supplier-context> ;
rdf:_7 <#select-products> .
@@ -26,7 +26,10 @@
each with unique pricing and inventory characteristics.
"""^^rdf:XMLLiteral .
- # Chart block
+ # Chart block (wrapped in ldh:Object per ContentMode contract)
+ <#top-selling-products-block> a ldh:Object ;
+ rdf:value <#top-selling-products> .
+
<#top-selling-products> a ldh:ResultSetChart ;
dct:title "Top selling products" ;
spin:query <#products-by-sales-query> ;
@@ -63,7 +66,10 @@ LIMIT 5""" .
market strengths and opportunities. The following charts break down revenue and product count by category.
"""^^rdf:XMLLiteral .
- # Revenue by category chart
+ # Revenue by category chart (wrapped in ldh:Object per ContentMode contract)
+ <#revenue-by-category-block> a ldh:Object ;
+ rdf:value <#revenue-by-category> .
+
<#revenue-by-category> a ldh:ResultSetChart ;
dct:title "Revenue by category" ;
spin:query <#category-revenue-query> ;
@@ -94,7 +100,10 @@ WHERE {
GROUP BY ?category ?categoryName
ORDER BY DESC(?revenue)""" .
- # Products by supplier chart
+ # Products by supplier chart (wrapped in ldh:Object per ContentMode contract)
+ <#products-by-supplier-block> a ldh:Object ;
+ rdf:value <#products-by-supplier> .
+
<#products-by-supplier> a ldh:ResultSetChart ;
dct:title "Products by supplier" ;
spin:query <#supplier-product-count-query> ;
diff --git a/demo/northwind-traders/root.ttl b/demo/northwind-traders/root.ttl
index 3046e19..4bb26a9 100644
--- a/demo/northwind-traders/root.ttl
+++ b/demo/northwind-traders/root.ttl
@@ -14,8 +14,8 @@
dct:description "Knowledge Graph representation of the Northwind Traders sample database" ;
rdf:_1 <#page-header> ;
rdf:_2 <#overview-intro> ;
- rdf:_3 <#sales-trend> ;
- rdf:_4 <#revenue-by-country> ;
+ rdf:_3 <#sales-trend-block> ;
+ rdf:_4 <#revenue-by-country-block> ;
rdf:_5 <#top-selling-products> ;
rdf:_6 <#top-manager-header> ;
rdf:_7 <#top-manager> ;
@@ -40,6 +40,9 @@
Explore key business metrics including sales trends, geographic distribution, and product performance. All visualizations are generated from live SPARQL queries over the RDF Knowledge Graph.