Home » A Python IndieAuth provider

Beto Dealmeida's avatar

A Python IndieAuth provider

An implementation of IndieAuth in Python

Approximate reading time: 3 minutes

Last week I started developing an RSS/Atom based news reader. I've been using Feedly[archived] to follow blogs, but also to follow music forums. Blogs have a good signal to noise ratio, but forums have too many posts, and I often wish I could "mute" a discussion thread, so that no more posts from a given discussion show up. I decided to create a small Flask[archived] app, using the Python feedparser[archived] library together with Celery[archived] to periodically fetch entries, and Svelte[archived] to display them on the frontend.

I started thinking about authentication, and since I didn't want to manage credentials I decided to use IndieAuth[archived]. IndieAuth is a protocol designed to allow authentication and authorization using only your website URL. It works the following way:

  1. You visit a 3rd-party website, app.example.com (the client), and type in your website URL (you.example.com) to login.
  2. The client fetches your website, looking for a link with the property rel=authorization_endpoint. This is something you should've set up, and corresponds to an endpoint that can represent you.
  3. The client sends you to the authorization endpoint. The authorization endpoint knows who you are (you should be logged in), and it asks if you want to confirm your identity to app.example.com.
  4. When you accept, the authorization endpoint sends you back to the client, with an authorization code.
  5. The client then uses the authorization code to talk to the authorization endpoint, which confirms that you are you.

I decided to write a Flask application that worked as an authorization endpoint, so I could understand the protocol better while setting up my website for IndieAuth. One of the problems I had was that, if you look at step 3, the authorization endpoint needs to know who am I. This requires logging in to the authorization endpoint, which is the problem I originally wanted to solve. At some point I probably need to login with a username and a password, but I didn't want to manage that.

So I decided to punt the authentication problem one more step, and implemented RelMeAuth[archived] in my authorization backend. RelMeAuth delegates authentication to an OAuth provider, defined by a link with the rel=me property. Basically this is how it works:

  1. You are sent to the authorization endpoint when the client asks it to confirm that you are you.example.com.
  2. The authorization endpoint doesn't know if you are you.example.com. It fetches your website, looking for a link with the property rel=me pointing to Github or Twitter (more providers could be added).
  3. The authorization endpoint sends you to Github (eg) so you can authenticate.
  4. When you authenticate and authorize sharing your information, you're sent back to the authorization endpoint.
  5. The authorization endpoint confirms that you're logged to the account specified in the rel=me link.

Basically, on your website you.example.com you add a link <a href="https://github.com/betodealmeida" rel="me">Github</a>. Then, if a website can confirm that you are indeed betodealmeida on Github they know you own you.example.com.

My identity provider is running on https://taoetc.org/[archived], hosting a simple h-card[archived] and declaring the authorization endpoint both in the HTTP header as well as in the HTML. If you run your own website you can use my IndieAuth service by adding the following lines to your HTML:

  <link rel="authorization_endpoint" href="https://taoetc.org/auth">
  <link rel="token_endpoint" href="https://taoetc.org/token">
  <!-- one or the other is needed -->
  <a href="https://github.com/$username" rel="me">Github</a>
  <a href="https://twitter.com/$username" rel="me">Twitter</a>

I haven't tested the Twitter authorization yet, only Github. Also, only use this if you trust me. If you don't, you can run your own instance. I named the service este-sou-eu[archived], which means "this is me" in Portuguese. I'll be adding detailed instructions of how to run it in the next few days.

(Also posted on IndieNews.)


You can engage with this post on Twitter or Webmention.