Unveiling WebFinger: A Symphony of Connectivity in the Digital Realm
WebFinger is a discovery protocol that facilitates the retrieval of additional metadata associated with a specific web address or identity. Imagine it as a digital business card for the web, providing a standardized method to inquire about and retrieve details such as profile information, public keys, or other relevant data. It is built on standards like HTTP requests and JSON Payload. WebFinger operates by allowing clients to query metadata related to a particular resource. The returned information can include a variety of data, aiding in the seamless integration and interoperability of decentralized web technologies.
One of the notable applications of WebFinger is in the realm of social networking. Clients can leverage WebFinger to fetch additional details about a user's URL, such as profile pictures, biographies, or other social information. Moreover, the protocol extends its utility to scenarios like email, where it can be used to retrieve public keys for encryption purposes.
In this Blogpost I will guide you through my process to create a webfinger endpoint to my page and host it. So let's get started.
Creating the server
I use a small webserver from nodejs, so I must initialize the env for it
npm init -y
npm install express body-parser
Next, I will implement the basic response implementation
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// Middleware for parsing JSON
app.use(bodyParser.json());
// WebFinger endpoint
app.get('/.well-known/webfinger', (req, res) => {
const resource = req.query.resource;
if (!resource) {
return res.status(400).json({ error: 'Resource parameter is required.' });
}
// Generate WebFinger response
const webFingerResponse = {
subject: resource,
links: [
{
rel: 'http://webfinger.net/rel/profile-page',
href: `https://example.com/profile/${resource}`,
},
// Add more links as needed
],
};
res.json(webFingerResponse);
});
// Start the server
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
This will host in the URL path .../.well-known/webfinger the JSON Webfinger response. In this case a small response with the given input. So start the app with
node app.js
Then call the following url
http://localhost:3000/.well-known/webfinger?resource=sascha@bajonczak.com
This will result in the simple webfinger information:
{
"subject": "sascha@bajonczak.com",
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"href": "https://example.com/profile/sascha@bajonczak.com"
}
]
}
So in this example, it will redirect to an example page to get a profile. Later at the end I will redirect it to my mastodon profile. Hey Mastodon.... Let's add Mastodon support.
Adding Mastodon support
So in fact that webfinger is for decentralized platforms, and I want to add support for Mastodon now. For this, I must adjust the script a little bit and add it to my mastodon account
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// Middleware for parsing JSON
app.use(bodyParser.json());
// WebFinger endpoint
app.get('/.well-known/webfinger', (req, res) => {
const resource = req.query.resource;
if (!resource) {
return res.status(400).json({ error: 'Resource parameter is required.' });
}
// Generate WebFinger response
const webFingerResponse = {
subject: resource,
links: [
{
rel: 'http://webfinger.net/rel/profile-page',
href: `https://example.com/profile/${resource}`,
},
{
rel: 'http://schemas.google.com/g/2010#updates-from',
href: 'https://mastodon.social/@sashca',
type: 'application/activity+json',
}
],
};
res.json(webFingerResponse);
});
// Start the server
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
The important part is this
{
rel: 'http://schemas.google.com/g/2010#updates-from',
href: 'https://mastodon.social/@sashca',
type: 'application/activity+json',
}
This will give the information about my mastodon account. After running and calling the webfinger again it will result in this
{
"subject": "sascha@bajonczak.com",
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"href": "https://example.com/profile/sascha@bajonczak.com"
},
{
"rel": "http://schemas.google.com/g/2010#updates-from",
"href": "https://mastodon.social/@sashca",
"type": "application/activity+json"
}
]
}
Adding Blog refernces
I think Mastodon is one way, so I want to publish to the Fediverse my blog articles too. So I declare in the webfinger my blog and also the definition where a user can subscribe to my blog (if needet). My complete definition looks now like this
....
{
rel: 'alternate',
type: 'application/rss+xml',
href: 'https://blog.bajonczak.com/rss/',
}
....
So my final result will redirect to the profile page to Mastodon, it adds also my blog to the webfinger method tool. The next step is to host it on my domain.
My Final Result looks now like this
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// Middleware for parsing JSON
app.use(bodyParser.json());
// WebFinger endpoint
app.get('/.well-known/webfinger', (req, res) => {
const resource = req.query.resource;
if (!resource) {
return res.status(400).json({ error: 'Resource parameter is required.' });
}
res.setHeader('Content-Type', 'application/jrd+json');
// Generate WebFinger response
const webFingerResponse = {
subject: resource,
aliases: [
'https://hachyderm.io/@Sascha',
'https://hachyderm.io/users/Sascha'
],
links: [
{
rel: 'http://webfinger.net/rel/profile-page',
type: 'text/html',
href: 'https://hachyderm.io/@Sascha'
},
{
rel: 'self',
type: 'application/activity+json',
href: 'https://hachyderm.io/users/Sascha'
},
{
rel: 'http://ostatus.org/schema/1.0/subscribe',
template: 'https://hachyderm.io/authorize_interaction?uri={uri}'
},
{
rel: 'http://schemas.google.com/g/2010#updates-from',
href: 'https://mastodon.social/@sashca',
type: 'application/activity+json',
},
{
rel: 'avatar',
href: `https://blog.bajonczak.com/content/images/2022/10/20221014_171637.png`,
type: 'image/png',
},
{
rel: 'alternate',
type: 'application/rss+xml',
href: 'https://blog.bajonczak.com/rss/',
}],
};
res.json(webFingerResponse);
});
// Start the server
app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
});
Hosting
So instead of installing different tools or other things, I create a small container for this and host it onto a webapplication in Azure.
Creating the container
So my Dockerfile looks like this
# Verwende ein offizielles Node.js-Image als Basis
FROM node:14
# Erstelle das Arbeitsverzeichnis
WORKDIR /usr/src/app
# Kopiere die Abhängigkeiten und das Anwendungscode in das Arbeitsverzeichnis
COPY package*.json ./
RUN npm install
COPY . .
# Setze die Standardumgebungsvariable für den Port
ENV PORT=3000
# Öffne den Port, den deine Anwendung verwendet
EXPOSE $PORT
# Starte die Anwendung
CMD ["node", "app.js"]
This must be placed in the same directory in which the app.js is located. I build and run it with the following command
docker build -t webfinger .
docker run -p 3000:3000 -d webfinger
I'll check it, and the response works from within the container
After pushing it onto a registry (for me it's hosted in dockerhub). I can install this into my Azure app service for now. Instead of handling complex startup commands to open up a port I use a docker-compose file for forwarding the internal request to the external http and https requests:
version: '3'
services:
app:
image: yourimage:latest
ports:
- 80:3000
- 443:3000
Final Testing
Now my webfinger definition is online, the result looks like this:
When I now go to mastodon and try to search for any user in my domain it will popup my avatar and link to my mastodon profile
Now it's your turn to increase my counter for followers ;)
Conslusion
In conclusion, webfinger is a good method to publish information in the decentralized world. It's like a business card on the internet and provides data that can be shared with other services. In this example, I used webfinger to populate my own domain to mastodon and add more meta information like my blog.
What's your opinion on this?