Journey to MIndie
Published by Matthew Turner on (Re-published on )
My journey to discovering IndieAuth, and implementing MIndie as a minimal out-of-the-box solution to add IndieAuth to your server.
Table of Contents
- Demo
- Background
- The Birth of MIndie
- Journey to IndieAuth + OAuth Compatibility
- The Birth of svn-auth
Demo
Projects:
POSSEd to YouTube
Background
Frustration with Backups
For years I have been frustrated with different backup software. Too many times I would install an application, change around the colours and other settings, use it for a few months or years; only to move to a new computer and that I neither remember what those settings were (so things just feel annoying) nor was I able to migrate those settings over. Developers simply did not seem to pay attention to moving to a new computer. Worse, backup software asked you to choose folders that mysteriously did not hold said settings!
Then I became a developer. So with my new found skills and tools I started digging into why and now I blame the Operating System. Turns out during the application installation, the Operating System, lets the developers choose to put whatever they want, wherever they want it! It is merely a common courtesy for developers to have their installer ask you where you would like things, a courtesy they don't actually have to abide by. For example, Visual Studio (the thick one) will let you designate an install directory and then only install a small few gigabytes or so where you designate but the larger 20+ GB of components has a hard-coded location (you can get around this by after-the-fact copying the component directory, then creating a symbolic link to “fix” the broken path, which is very technical). For another application, the fairly old Star Wars: Pit Droids, I actually put my entire filesystem under the subversion (SVN) revision control system (using TortoiseSVN) to detect any new files or modified files. Lo and behold, I could create a new game save and it did not show up anywhere (my best guess is that it is buried in the Registry…yikes), making it technical and likely missed during migration to another computer regardless of your backup software.
Backup Solution
As a developer, I learned about archaic (ex. subversion) and more modern (ex. GIT) strategies used by software developers to backup their codebase. Do you remember when Google seemed super innovative in the 2010s by coming out with Google Docs and the ability to see the last few edits made? Turns out devs have been using far more powerful tools for over a decade before! Could these tools be used as a generic backup strategy for user files? Yes! Though not as “optimally” as it is for code.
I chose subversion because it mimics the filesystem (easy to understand), you can get it running fully localhost pretty easily, and you can ignore the complicated dev-specific feature of “branches”. Of course I have gone further and started setting up my own in-house server to host it…
But then I wanted “Shareable” Backups
Turns out that as you grow old into an adult, have kids, and find that your family wants to see pictures and notes of growth as your children age…it becomes much nicer if you can share your backup copy with them directly instead of duplicating it in various chats, postings, et cetera.
AND THEN you realize that you don't want to administer and manage accounts for family members on your system when they don't want those accounts either; and, anyway, they will probably forget their password every second day.
Outsourcing Identity - OpenID Connect
Roughly a year-and-a-half ago, I configured the authorization of a new application for a company. They had other teams who had written other applications and had devised their own client library on top of OpenID Connect against the Identity Provider (IdP) they chose, and it was…well it worked. They had a fairly complicated process and I did not really have to learn much about OpenID Connect.
Roughly six months ago, I started configuring the authorization of a new application for a different company. This time I was using the lower-level OpenID Connect library directly as well as looking at the provider options. I got to learn about OpenID Connect and ran head-first into a complexity that was fine for the company, but would not be fine for my personal life: you have to register and configure every provider individually. What is more, while you can support multiple providers, it does not seem to be typical and adds some complexity. Either way, you have to hope that all of your users have or are willing to have the provider(s) you chose to support.
The Birth of MIndie
Discovering IndieAuth
Turns out there is a better option: IndieAuth! Similar to the BYOD (Bring Your Own Device) for mobile phone plans, it is like a BYOIdP (Bring Your Own Identity Provider) for personal websites. A big change is that, instead of providing an email, users now provide a URL to their personal webpage and can log in with their own configured provider. Even better, IndieAuth.com provides a service so that you can re-use your existing social media logins (no new account needed). For family members who are tired of more accounts, this is really nice! For me, no registration is required to allow access for them and anyone new in the future!
Simple, right? …right?
One might assume that because IndieAuth is “built upon” OAuth, that simply providing authentication with IndieAuth allows you to authorize with OAuth. And you would be dead wrong. Rather, IndieAuth can be (and, as I found out, often is) used completely independently from OAuth and requires additional configuration to make it compatible.
I ignorantly grabbed SelfAuth so that I could play around with configuring mod_oauth2 in front of my subversion. Making it compatible has taken 3 months…
IndieWeb Mentality
Although the IndieWeb community (who developed the IndieAuth protocol) has a great Getting Started page and IndieWebify guide that makes it easy to join for non-technical people, they are largely expecting you to be a website enthusiast who is willing to develop your own implementation. This spreads the beneficial Pluralism they believe in, but it also means there is no real out-of-the-box solution that you can play around with to find out whether you like it in the first place.
And I need to be quite clear here: they have plenty of almost out-of-the-box solutions (WordPress plugin, Micro.blog, Bridgy, Known, 11ty, ProcessWire, IndieLogin.com, et cetera). They are probably slick to sign up and get started fast. However, they range from social media silo replacements to an all-in-one platform (I am looking at you, WordPress) to a CMS (Content Management System). There is no library that you can install and have IndieAuth added to your server. Especially without a new account or private network support.
More importantly, none of these solutions are compatible with serving files from subversion.
Journey to IndieAuth + OAuth Compatibility
Understanding IndieAuth and OAuth
While I have a much more useful description on MIndie, there are a few key highlights I want to include here.
- SelfAuth provides an authorization code
- MinToken provides an access token
- mod_oauth2 requires an identity token (the process of exchanging an access token for an identity token is called introspection)
- SelfAuth+MinToken do not support Metadata Discovery (they rely on the deprecated mechanism for IndieAuth)
- SelfAuth is not intended for multi-user
It is also very important to note that I could have saved effort and time by tying myself to my social media accounts and not supporting a private network. After all, I started this so that I could share it externally…
Developing Introspection
It took me 3 solid weeks of configuring, reading specifications, misunderstanding IndieAuth, finding MinToken, figuring out that the bearer token needs to be a cookie (not the header), and just generally realizing that I needed introspection in the first place before I was successful in having mod_oauth2 find and accept a token from an IndieAuth IdP.
The results of this effort, because SelfAuth and MinToken have yet to accept the code changes at the time of this writing, became the birth of MIndie. The IdP and Client can be cloned and will talk to each other after a little bit of configuration. No need to dive into the implementation and specifications and just general development.
The first and biggest hill to climb is that Apache HTTPd processes requests in the pipeline: Authenticate → Authorize → Application Handler. I wanted to take the most advantage of this because blocking requests as early in the pipeline can reduce your attack surface and aid in defense in depth, two very important security principles. It is especially important to provide the security before the Application Handler because not all applications will provide quality security measures. In the case of subversion, the file retrieval module resides at the Application Handler layer and does not provide any security measures. Instead, you are expected to configure the included authorization module, or configure other modules, to block requests before they reach the file retrieval layer.
Unfortunately, libraries such as the [IndieAuth Client provided by the IndieWeb community](https://github.com/indieweb/indieauth-client-php) reside at the Application Handler layer as well. IndieAuth implementations seem to assume that the application itself is importing the library and doing the authentication check. But Apache does not let you call one Application Handler and then pass off to another, nor does it let you cycle back and re-do the pipeline. This is why no code (such as PHP or Python) residing within subversion will run. Instead, you would have to checkout a subversion working copy, and then serve the checkout through Apache. It also means existing IndieAuth implementations can't just "add to your server" like a real out-of-the-box solution would (such as mod_oauth2). They also don't contribute to reducing your attack surface and aiding defense in depth so easily.
Hope is not lost! Due to the redirects that are inherent within OAuth and protocols built on top of it, you can serve a login endpoint with a different Application Handler than your content endpoints. Then enables you to write two applications that a browser will see as one. It creates a flow thus:
- Browser tries to access a content endpoint
- Apache will deny access and suggest redirecting to a login endpoint
- Browser tries to access the login endpoint
- Apache passes control to IndieAuth application
- IndieAuth application communicates with Browser to perform login
- IndieAuth application will save a cookie on the Browser and redirect to the original content endpoint
- Browser tries to access a content endpoint
- Apache will grant access (through mod_oauth2, who reads the cookie) and pass control to Content application (subversion)
- Content application (subversion) will return content to the Browser
It is quite important to note that because these are two independent applications operating as though they are one, they need to be able to pass information across their boundary, and they need the Browser to do the labour. Hence the need for cookies.
The second hill to climb is that since IndieAuth can be used completely independently from OAuth, there is no requirement for introspection. However, to throw information over the independent application fence, you are going to require that the IdP either supports introspection or will return a JWT (signed with JWKS) or some similar complexity. Vanilla SelfAuth+MinToken do not support this. In fact, many wild IndieAuth IdPs do not. Until they do, MIndie will work best when MIndie is also the IdP on the other side.
Is mod_oauth2 Compatibility Enough?
While mod_oauth2 is technically an authorization module (actually it integrates with both mod_authn_core and mod_authz_core), at its most simple usage it completely resides in the Authentication layer of the Apache request pipeline. Any added authorization directives it can add are against the claims in the identity token that it used introspection to retrieve. Meaning the IdP is in control of whether the request is authorized to proceed to the next layer.
Alas, my goal (do you still remember it?) is to share individual files from my backup with external family and friends. I want to be able to set a property on the file to say “here is a list of people to access this” without any listed name requiring registration (me and those living with me are ok) on my system.
Fortunately, subversion allows for custom versioned properties! Unfortunately, that means I have to write my own module for the Authorization layer of the Apache request pipeline.
The Birth of svn-auth
Although I was not going to spend the time writing a full Apache module, I did find the nifty mod_authnz_external that lets you prototype and easily break things!
While I won't go into detail here, I was successful. That is, I can list an IndieAuth user (their webpage URL) in a SVN property (called authz:read
) to grant their request access. This took a couple of months with the work more spread out.