Mojolicious::Plugin::WebFinger - Serve and Retrieve WebFinger Documents


  # Mojolicious

  # Mojolicious::Lite
  plugin 'WebFinger';

  # Will serve XRD or JRD from /.well-known/webfinger

  # Discover WebFinger resources the blocking ...
  print $c->webfinger('')

  # ... or the non-blocking way
  $c->webfinger('' => sub {
    my ($xrd, $header) = @_;
    # ...


Mojolicious::Plugin::WebFinger provides several functions for the WebFinger Protocol. It supports .well-known/webfinger discovery as well as Host-Meta and works with both XRD and JRD.



  # Mojolicious
  $app->plugin(WebFinger => {
    expires => 100,
    secure  => 1

  # Mojolicious::Lite
  plugin 'WebFinger';

Called when registering the plugin. Accepts the optional parameters secure, which is a boolean value indicating that only secure transactions are allowed, and expires, which is the number of seconds the served WebFinger document should be cached by the fetching client (defaults to 10 days). These parameters can be either set on registration or as part of the configuration file with the key WebFinger.



  # In Controllers:
  my $xrd = $self->webfinger('');

  # Only secure discovery
  my $xrd = $self->webfinger('', -secure);

  # Use lrdd with host and resource description
  my $xrd = $self->webfinger(
    '' => '', -secure

  # Use 'rel' parameters
  my $xrd = $self->webfinger(
    '' => ['describedBy'], -secure

  # Use non-blocking discovery
    '' => [qw/describedBy author/] => sub {
      my $xrd = shift;
      # ...
    } => -modern);

  # Serve local WebFinger documents
  my $xrd = $self->webfinger('me');

Returns the WebFinger resource as an XRD object. Accepts the WebFinger resource, an optional array reference of relations, and an optional callback for non-blocking requests. The appended flag indicates, how the discovery should be done. -secure indicates, that discovery is allowed only via https. -modern indicates, that only /.well-known/webfinger is discovered over https. -old indicates, that only Host-Meta and lrdd discovery is used.



  # Establish a callback
    fetch_webfinger=> sub {
      my ($c, $host, $res, $header) = @_;

      # Get cached document using M::P::CHI
      my $doc = $c->chi->get("webfinger-$host-$res") or return;

      # Get cached headers
      my $headers = $c->chi->get("webfinger-$host-$res-headers");

      # Return document
      return ($c->new_xrd($doc), Mojo::Headers->new->parse($headers));

This callback is released before a WebFinger document is retrieved from a foreign server. The parameters passed to the callback include the current controller object, the host's name and the resource name.

If an XRD object associated with the requested host name is returned (and optionally a Mojo::Headers object), the retrieval will stop.

This can be used for caching.

The callback can be established using the callback helper or on registration. Callbacks may be improved for non-blocking requests in the future.


  if ($c->callback(prepare_webfinger => sub {
    my ($c, $res) = @_;
    if ($res eq '') {
      $c->stash('profile' => '');
      return 1;
  })) {
    print 'The requested resource exists!';

This callback is triggered before a WebFinger document is served. The current controller object and the requested resource is passed. A boolean value indicating the validity of the resource is expected. A rendered response in the callback will be respected and further serving won't be processed.

Data retrieved for the resource can be passed to the stash and rendered using the before_serving_webfinger hook.

The callback can be either set using the callback helper or on registration. Callbacks may be improved for non-blocking requests in the future.



    before_serving_webfinger => sub {
      my ($c, $res, $xrd) = @_;
      if ($c->stash('profile')) {
        $xrd->link(profile => { href => $c->stash('profile') } );

This hook is run before the requested WebFinger document is served. The hook passes the current controller object, the resource name and the XRD object.


    after_fetching_webfinger => sub {
      my ($c, $host, $res, $xrd, $headers) = @_;

      # Store document in cache using M::P::CHI
      $c->chi->set("webfinger-$host-$res" => $xrd->to_pretty_xml);

      # Store headers in cache
      $c->chi->set("webfinger-$host-$res-headers" => $headers->to_string);

This hook is run after a foreign WebFinger document is newly fetched. The parameters passed to the hook are the current controller object, the host name, the resource name, the XRD object and the headers object of the response.

This can be used for caching.


The route /.well-known/webfinger is established as the lrdd endpoint webfinger. This plugin depends on this route, and the resource and rel attributes. Although other routes are possible for WebFinger/lrdd in older drafts of the specification and different forms for the resource definition, this is assumed to be a future-proof best practice.


The examples/ folder contains a full working example application with serving and discovery. The example has an additional dependency of CHI. It can be started using the daemon, morbo or hypnotoad.

  $ perl examples/webfingerapp daemon

This example may be a good starting point for your own implementation.

A less advanced application using non-blocking requests without caching is also available in the examples/ folder. It can be started using the daemon, morbo or hypnotoad as well.

  $ perl examples/webfingerapp-async daemon


Mojolicious (best with SSL support), Mojolicious::Plugin::HostMeta.


This plugin is part of the Sojolicious project.


Copyright (C) 2011-2018, Nils Diewald.

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.