Automate Mobilizon

Automate Mobilizon
Photo by Towfiqu barbhuiya / Unsplash

As I'm hacking a Mobilizon instance to push into the fediverse events fetched from different sources (e.g. the ticket selling platoforms popular in Italy, like VivaTicket), I have to put together some PHP script to automatically interact with the poorly documented Mobilizon API.

Even for the first step - the OAuth authentication - I had to iterate multiple times to obtain a working flow, enabled by the so-called Device Code grant type, which permits non-interactive authentication (at least, after the first abilitation) and unattended automations.

Here the full script intended to generate a client ID, a secret, an access token (to be then used with the GraphQL API) and a refresh token. It displays a URL and a code to be manually copied into the Mobilizon instance (when authenticated with the preferred user, of course).

<?php

/*
    Stupid function to perform a POST with cURL
*/
function doPost($url, $params)
{
    $curl = curl_init();

    $postfields = [];
    foreach($params as $name => $value) {
        $postfields[] = sprintf('%s=%s', $name, urlencode($value));
    }

    $postfields = join('&', $postfields);

    curl_setopt_array($curl, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => "POST",
        CURLOPT_POSTFIELDS => $postfields,
        CURLOPT_HTTPHEADER => [
            "content-type: application/x-www-form-urlencoded"
        ],
    ]);

    $response = curl_exec($curl);
    $err = curl_error($curl);
    $ret = json_decode($response);
    curl_close($curl);

    return $ret;
}

/*
    Configure here the URL of your Mobilizon instance.
    $app_website and $app_redirect_uri can be any URL, those will never be used
*/
$mobilizon_instance = 'https://your.mobilizon.instance.com';
$app_name = 'My APP';
$app_scope = 'write:event:create write:event:update write:event:delete write:media:upload write:media:remove write:group:create write:group:update write:group:delete';
$app_website = 'https://www.doesntmatter.com/';
$app_redirect_uri = 'https://www.doesntmatter.com/callback';

/*
    Step 1: register the app to obtain a client ID and a secret
*/

$ret = doPost($mobilizon_instance . '/apps', [
    'name' => $app_name,
    'redirect_uri' => $app_redirect_uri,
    'website' => $app_website,
    'scope' => $app_scope,
]);

$client_id = $ret->client_id;
$client_secret = $ret->client_secret;
$scope = $ret->scope;

/*
    Step 2: ask for device authentication
*/

$ret = doPost($mobilizon_instance . '/login/device/code', [
    'client_id' => $client_id,
    'scope' => $scope,
]);

echo sprintf("Now go to\n%s\n", $ret->verification_uri);
echo sprintf("and digit the code\n%s\n", $ret->user_code);

/*
    Step 3: wait for actual authentication by the user
*/

$device_code = $ret->device_code;
$grant_type = 'urn:ietf:params:oauth:grant-type:device_code';

for ($i = 0; $i < 30; $i++) {
    try {
        $ret = doPost($mobilizon_instance . '/oauth/token', [
            'client_id' => $client_id,
            'device_code' => $device_code,
            'grant_type' => $grant_type,
        ]);

        if (isset($ret->access_token)) {
            /*
                Save the parameters in your configuration file
            */
            echo $client_id . "\n";
            echo $client_secret . "\n";
            echo $ret->access_token . "\n";
            echo $ret->refresh_token . "\n";
            echo $device_code . "\n";

            echo "DONE\n";
            break;
        }
    }
    catch(\Exception $e) {
        // dummy
    }

    sleep(2);
}