masto-id-connect

Functions for authenticating a user against a Mastodon API; server discovery, client registration, token exchange, and user info fetching.

Usage no npm install needed!

<script type="module">
  import mastoIdConnect from 'https://cdn.skypack.dev/masto-id-connect';
</script>

README

Masto ID Connect

Why maintain your own auth system when you can use someone else's?

Issuer discovery, client registration, and user authentication methods for Mastodon

This library provides a simple set of functions for authenticating a user against a Mastodon API. It only provides methods relevant to authentication - server discovery, client registration, token exchange, and user info fetching.

The methods provided are similar to those that you might find in a general OIDC client library. Mastodon does not currently support OIDC, but a feature request has been made. In the meantime you can use this library to achieve the same goal using Mastodon's proprietray API.

Usage

import http from 'http';
import mastoIdConnect, { OOB } from 'masto-id-connect';

const masto = mastoIdConnect();

// First we must discover the issuer and register our client.
// You will only need to do these once - here we're doing it
// at the start of our script, but in reality you may want to
// do it dynamically when a user inputs their mastodon URL.
// In that case you'll need to store the results in a database
// so you can look them up again later.
const kithKitchen = await masto.discoverIssuer('https://kith.kitchen');
const kkClient = await masto.registerClient(kithKitchen, {
    clientName: 'Example Client',
    // The redirect URI to return the user to your webserver after they log in to mastodon.
    // You can also use the out-of-band approach by passing the OOB const
    redirectUri: 'http://localhost:8080/exchange-token'
});

// This is an example webserver - obviously yours will be different but the principle is the same
http.createServer(async (req, res) => {
    const url = new URL(req.url, 'http://localhost:8080');
    switch(url.pathname) {
        case '/authenticate':
            // This is our user's entry point - direct the user to the mastodon auth page.
            // Here we have hardcoded kith.kitchen, but you could use the discover and register
            // methods to allow dynamic authentication against any instance the user wants.
            const kkUrl = masto.getAuthUrl(kithKitchen, kkClient);
            res.statusCode = 303;
            res.setHeader('Location', kkUrl);
            res.end();
            return;
        case '/exchange-token':
            // Get the issuer and the authentication code from the request
            // If you're using the out-of-band methdod, you don't need this step
            // since the user will paste the code directly into your app.
            const { issuer, code } = masto.parseResponse(req);

            // Here we check that the issuer is our hardcoded instance
            // But you could use it to look up your issuer and client details
            // from a database if you've stored them there.
            if(issuer !== 'https://kith.kitchen') {
                res.statusCode = 500;
                res.end('Cannot authenticate against that instance');
                return;
            }

            // Next we get our authentication token
            const token = await masto.exchangeToken(kithKitchen, kkClient, code);

            // You could use this token to browse the mastodon API now - see the masto docs for more
            // Instead we are going to get the user's info. This is enough to log the user into our website
            const userInfo = await masto.getUserInfo(kithKitchen, token);

            // For more about the userInfo object, see [the open ID spec](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)
            res.end(`You are ${userInfo.name} and your URL is ${userInfo.sub}`);
            return;
    }
}).listen(8080);

mastoIdConnect

mastoIdConnect.MastoError

Class representing a Mastodon API error

Kind: static class of mastoIdConnect

new exports.MastoError(code)

Param Type Description
code String The mastodon api error code

mastoIdConnect.OOB

Out of band URN - use this as the redirect_uri for non-browser-based applications

Kind: static constant of mastoIdConnect

mastoIdConnect.default(protocol, issuerKey)

Create an instance of the Mastodon auth library

Kind: static method of mastoIdConnect

Param Type Description
options.request function Method for making https requests, having the same signature as https.request (which is the default value)
protocol string Protocol to use when making http requests, including '://'. Defaults to 'https://'
issuerKey string Key to use as the issuer identifier in the redirect URL's search params. Defaults to 'issuer

mastoIdConnect~discoverIssuer(Origin) ⇒ object

Get document describing oauth endpoints for the Mastodon instance This is not strictly needed but it helps if you don't know whether your url has a masto API or not

Kind: inner method of mastoIdConnect
Returns: object - An object with issuer, authorization_endpoint and token_endpoint urls

Param Type Description
Origin string The url or domain name for the instance

mastoIdConnect~registerClient(issuer, options) ⇒ Object

Register your client with the Mastodon instance

Kind: inner method of mastoIdConnect
Returns: Object - Client object

Param Type Description
issuer Object Issuer object returned by discoverIssuer
options Object Client options containing redirectUri and clientName

mastoIdConnect~getAuthUrl(issuer, client) ⇒ string

Generate the URL to redirect the user to in order to authorize them

Kind: inner method of mastoIdConnect
Returns: string - URL to redirec the user to

Param Type Description
issuer Object Object returned by discoverIssuer
client Object Object returned by registerClient

mastoIdConnect~parseResponse(req)

Get the issuer and code from an incomming request. Based on requests coming in when using http(s).createServer This step is not required if you're using the OOB URN

Kind: inner method of mastoIdConnect

Param Type Description
req https.IncommingMessage The client request object received by the server

mastoIdConnect~exchangeToken(issuer, client, code) ⇒ Object

Exchange your auth code for an auth token. The auth token is what lets you actually make requests.

Kind: inner method of mastoIdConnect
Returns: Object - Object containing access_token and token_type
Throws:

  • MastoError When an error is returned by the oauth endpoint
Param Type Description
issuer Object Object returned by discoverIssuer
client Object Object returned by registerClient
code string Code returned by parseResponse (or provided by user input if using OOB URN)

mastoIdConnect~getUserInfo(issuer, token) ⇒ UserInfo

Get information about the authenticated user. Presents information in the same format as if you were accessing an OIDC user info endpoint. For more information see the open ID spec

Kind: inner method of mastoIdConnect
Returns: UserInfo - Userinfo object

Param Type Description
issuer Object Object returned by discoverIssuer
token Object Object returned by exchangeToken

mastoIdConnect~UserInfo : Object

Information about the user, structured as an OIDC claims document

Kind: inner typedef of mastoIdConnect
See: OIDC standard claims documentation
Properties

Name Type Description
sub string The ID/URL of the actor (subject)
name string The display name of the actor
nickname string Alias of name
preferred_username string The actor's preferredUsername
profile string Alias of sub
picture string The URL of the actor's avatar (icon.url)