About two weeks ago, I started thinking about IndieAuth. I have implemented a few IndieWeb specifications in the past but IndieAuth was one that I had put to the back of my mind until recently. I was not confident in implementing an authentication endpoint so I decided to move on to other projects. I just came back to the spec and, with some encouragement from the people in the IndieWeb chat, realised that there was no reason why I should not try and build an IndieAuth endpoint. So I did. Now I have an IndieAuth endpoint that I can use to authenticate to any service that uses IndieAuth for authentication.
In this article I am going to share some basics about IndieAuth and a few notes from my experience building my own IndieAuth endpoint.
What is IndieAuth?
The traditional OAuth spec lets you authenticate as a user on one site to another which is useful if you want to use, say, your Google account to create an account on Kaggle. But OAuth is platform-specific. IndieAuth extends OAuth so that you can authenticate to a website using a URL or a domain name. This has a range of applications.
Consider this scenario. I have a tool that lets me publish content to my website. I could authenticate to that tool with a simple password but that relies on adding account management. Using IndieAuth, I can authenticate to the tool using my domain name. After verification, my authentication server can say to my content publishing tool "hey, James just proved he owns jamesg.blog. He just said that you can publish content on his site. Sign James in and let him publish content as jamesg.blog on your site."
The flow for IndieAuth goes like this:
- James signs in to prove he is jamesg.blog.
- James sees a message that his publishing tool wants him to sign in as jamesg.blog.
- James reads the publishing tool's request and approves it.
- The authorization server communicates with the publishing tool to confirm I am who I say I am.
- Another server creates a token that the publishing tool can use to verify my identity whenever necessary.
You may be wondering: how do "sign in to prove that he is jamesg.blog?" I can do that in any number of ways. The IndieAuth specification leaves authentication up to me. I could just use a basic passphrase. Or I could add a full account management system. But these are proprietary and would require setting up a database. This would add a lot of overhead to my implementation. I chose instead to add RelMeAuth, a method of authentication that lets you confirm your identity using rel=me links on your website.
RelMeAuth is when a service looks for all rel="me" links on your site and treats the destinations of those links as places you have verified are connected to you on the internet. For example I have a link that looks like this on my site homepage on jamesg.blog:
<a rel="me" href="https://twitter.com/capjamesg">Twitter</a>
The rel="me" attribute tells software that I own the Twitter handle @capjamesg. This means that software can know that if I authenticate as @capjamesg on Twitter, I must own the domain name jamesg.blog because I made a connection between the two with a rel="me" link. I have other rel="me" links on my homepage too, such as one to Instagram and one to GitHub.
When I "sign in to prove I am jamesg.blog," my IndieAuth server looks at my website home page for any links with a rel="me" attribute. I am then asked to authenticate using the OAuth services provided by any of the websites I have linked to. Right now, my endpoint only supports Twitter and GitHub authentication because those were the easiest to implement and will likely both be used by me. I also have a passwordless authentication method but that relies on separate logic and is not associated with rel="me".
Let's go back to the example of signing into my publishing software again.
I am first asked to sign in to prove I am jamesg.blog.
My authentication server looks at jamesg.blog and says "hey, there are a few rel='me' links on this page." If a link points to a site that is supported by the authentication server (for example, Twitter), then I am allowed to authenticate using that method. I currently see a page like this:
When I click on the Twitter or GitHub links, I am asked to sign in on their sites. After I sign in, my authentication server gets a code and verifies that I have in fact signed in as the person I linked to on my home page (capjamesg on both Twitter and GitHub). If my authentication server says that I have signed in as someone linked in a rel="me" link, the server knows I am jamesg.blog.
Why I built my own IndieAuth server
I built my own IndieAuth server to explore the world of authentication a bit more. Before working on this server, I didn't really know how IndieAuth, which I was using to sign in to many sites, worked. By reading the specification and associated materials (the IndieWeb wiki was a big help!), I learned what IndieAuth is, how it works, and what RelMeAuth is. I have a feeling there will be so much more to learn because the IndieAuth specification itself is still evolving and there are many interesting discussions happening that may affect my implementation.
I also wanted to take control over another part of my internet presence. By having my own IndieAuth endpoint, I can sign in to a website using a service I built and own, as long as that site implements IndieAuth.
I am happy with the progress I have made on my IndieAuth server. I can sign into all of my services (for example, my Micropub server or my Webmention endpoint) using my authentication endpoint. I have been testing the server with sites like OwnYourSwarm to make sure that authentication works as expected. There are still a few bugs to iron out but the tool has been deployed and is now in active use. I also open-sourced the code on GitHub so you can see how I implemented the IndieAuth specification. My implementation was written in Python with Flask.
Comments and reactions
Respond to this post by sending a Webmention.