Tinkering with Mastodon, Keycloak, and Domino

Nov 10, 2022, 1:01 PM

Tags: admin keycloak

Because of what I'll euphemistically call the current historical moment on Twitter, I (like a lot of people) decided to give another look at Mastodon. The normal way one would use it would be to sign up at mastodon.social and be on one's merry way, treating it just like a slightly-different Twitter.

However, Mastodon is intentionally designed to be federated in a way similar to email, and the software is available on GitHub complete with scripts for Docker Compose, Vagrant, and so forth. So I went and did that, setting up my currently-barely-used account at @jesse@pub.frostillic.us.

That on its own isn't particularly notable, nor are the specifics of how I set it up (it was a hodgepodge of a couple posts you can find by looking for "mastodon docker compose"). What I found neat for our purposes here was the way I could piggyback authentication onto stuff I had recently done with Keycloak. Keycloak, incidentally, was the topic of today's OpenNTF webinar, so, if you didn't see it, check back there for the replay when it's posted.

Having done the legwork for setting up Keycloak backed by Domino LDAP for my earlier tinkering, the setup to work with Mastodon was pretty straightforward (as far as these things go). I did the professional thing and took the basic config from a StackOverflow post, tweaking it to suit my needs.

The main Domino-y thing I wanted to tweak here was the username that I ended up with on Mastodon. Internally, the Domino short name for my account is "jgallagh", but I like to go by "jesse" when in an environment small enough to get away with it. So I cracked open the names.nsf subform I had added years ago for POSIX and SSH pubkey purposes and added a Mastodon section:

Screenshot of a 'Mastodon Attributes' section in a names.nsf

(apologies for how bad the new-era fonts look in my poor old Windows VM)

Then, I told my Mastodon config about that field for the UID:

OIDC_DISPLAY_NAME=frostillic.us Auth
OIDC_CLIENT_ID=<client id>
OIDC_CLIENT_SECRET=<client secret>
OIDC_REDIRECT_URI=https://<mastodon URL>/auth/auth/openid_connect/callback

On Keycloak, I made a new realm to cover this sort of "personal" setup to be able to split the user pool and then added a Client definition for Mastodon. I set it up as "Access Type" "confidential" and grabbed the client ID and secret for the config above and then configured the Redirect URI. To get the custom username field over from LDAP, I added a "user-attribute-ldap-mapper" Mapper in the LDAP User Federation definition to bring it in. Then, back in the Client definition, I added a "User attribute" token mapper to the config to bring this in as well so it's added to the JWT.

That covered the auth config, and it's been working well since. When you have OIDC configured in your Mastodon config, it sprouts a button below the main login mechanically labeled "OPENID_CONNECT":

Screenshot of a Mastodon login form with OIDC configured

Clicking that will send you to the configured Keycloak page to do the OIDC dance and, when all goes well, back to a freshly-configured Mastodon account.

Now, technically, this doesn't really gain me much that I couldn't have gotten by configuring the users separately in the Mastodon instance, but the experience is useful. I'm gradually getting really sold on the idea of having a multi-purpose Keycloak instance to handle authentication and authorization. Most of the time, it's a thin layer over what you could get by pointing to Domino LDAP from these disparate apps themselves. However, there are some benefits in that Keycloak is now the only one that has to deal with Domino's weird LDAP and also this gives me a lot of room for fine-grained control and federation with other providers. It's just neat.

Commenter Photo

JD - Nov 23, 2022, 12:35 AM

hey Jesse - thanks for posting this. I have Keycloak backed by a Zentyal instance and want to set up Mastodon to auth to it. Three questions:

  1. is it possible to only have OIDC?
  2. where the heck do all those environment variables actually go?
  3. how did you do the setup in Keycloak for Mastodon? I gather you have to create a "client" for it on the Keycloak side. there are a lot of settings after that that I guess are fine left to their defaults or blank? thanks!
Commenter Photo

Jesse Gallagher - Nov 23, 2022, 4:34 PM

I don't know if it's possible to have only OIDC available, though I think that may be blocked by the desire/need to have the ability to log in as the original Mastodon admin user in case things go sideways. What you could do - and I've done with a few things - is add CSS that targets the login form to hide it.

In my case (using the Docker Compose instructions), I put the environment variables in .env.production in the working directory. The Compose instructions include that file inside the Mastodon containers as environment variables.

That's about right for the Keycloak config. I created a new client with "Access Type" set to "confidential", the root and admin URLs set to the base URL of the Mastodon instance, and the redirect URIs set to that plus /*. Then, I added in the "mastodonusername" mapper bit from the post. I didn't add any new Client Scopes or the like.

Commenter Photo

JD - Nov 23, 2022, 6:56 PM

thanks! worth noting that in recent versions of Keycloak (20, at least), there is no "access type" setting, rather you have to turn on the "client authentication" switch and then hit "save," after which you'll see a "credentials" tab appear. then you can get the client secret.

Commenter Photo

JD - Nov 26, 2022, 11:38 AM

guess what! it's an environment variable! https://github.com/mastodon/mastodon/discussions/19813#discussioncomment-4127394

Commenter Photo

JD - Nov 26, 2022, 11:43 AM

(having only OIDC, that is.)

Commenter Photo

Jesse Gallagher - Nov 28, 2022, 9:19 AM

Oh nice - I may turn that on for my instance, since I only extremely rarely will need the local admin account, and could re-enable it there. One fewer attack vector would be nice.

Commenter Photo

JD - Dec 17, 2022, 3:32 PM

side note: I couldn't make your mapping trick work. instead I had to set OIDC_UID_FIELD to "preferred_username," everything was golden after that.

New Comment