[RFC] General API Authentication Method

Skip to first unread message

Tyler Shuster

Oct 7, 2020, 2:42:04 PMOct 7
to urbit-dev
Part of increasing adoption on Urbit involves making it more available for developers as a platform. Josh & I have talked about this a bit and I’m sure many of you have as well. I’ve been working on a document to PR to urbit/docs that summarizes the method by which developers can implement “airlock,” otherwise known as urbit’s API. https://gist.github.com/tylershuster/74d69e09650df5a86c4d8d8f00101b42 ( I would appreciate your feedback on that doc in the comment box ).People seem to assume that you need to learn a rather esoteric language to develop on urbit, and this poses a high barrier to entry for developers developers developers developers. This doc will go a long way in ameliorating those concerns, I hope.

However, I’m concerned that the current method of authentication is a bit convoluted, even with documentation.

The current API authentication uses the following flow:

1. make a POST to /~login with your code as form data.
2. receive a cookie back in the set-cookie headers
3. send that cookie on any subsequent requests

This works, basically.  Here’s what I like about it, before I say what’s wrong: It uses existing mechanisms (form data, set-cookie, cookies automatically sent)
I would like to preserve that simplicity, and now that CORS has some tools it works for the browser pretty well.

There are some problems, however. From a social perspective, it’s a bit unprofessional for a general purpose API. It’s fine when you’re working with one client but I worry that it will draw criticism for other reasons than I can think of here:

For instance, browsers don’t allow you to manually set Cookie headers so if you’re using a library like axios or a fetch polyfill you get some behavior that’s hard to work around.
Another problem is just ease of use. Most people are used to sending a POST variable for authentication, or a header that’s….not cookie. Basically cookies are for browsers and we’re working on expanding from the browser context to increase adoption.

I wonder if we could progressively enhance auth to follow something like the following behavior:

1. Make a POST to /~login with your code as form data. (this feels fine to me)
2. Receive both the current set-cookie header (for browsers) as well as a JSON object with the same info: {ship: ‘~zod’, key: ‘12345’}
3. Send that structured info with subsequent requests with Basic Authentication. Let the browser use cookies as it does currently.

It *seems* to me that we could keep the existing behavior and account for this.

I’d like to know your thoughts. This isn’t an immediate concern, but I feel like it’s fairly low-work, high-reward.

Daniel Clelland

Oct 8, 2020, 11:05:49 PMOct 8
to Tyler Shuster, urbit-dev
My two cents:

I'd much prefer a JSON object - in UrsusAirlock I do some weird things to get the ship name out of the cookie header, and it feels fragile to me.

I'd also rather just write my own session management thing than pretend all my HTTP requests happen in a web browser and hope the (otherwise somewhat opaque) cookie store behaves predictably (it does all seem to work fine at present, though).

- Daniel

To unsubscribe from this group and stop receiving emails from it, send an email to dev+uns...@urbit.org.


Oct 9, 2020, 1:12:46 PMOct 9
to Daniel Clelland, Tyler Shuster, urbit-dev
First of all, friendly reminder that Eyre and its endpoints weren't explicitly designed with "airlock"-like use cases in mind. Discussion/pushing for changes in this area is entirely justified.

Another weakness of cookies that you didn't list is that they're for sessions, which expire. You can't "set and forget" anything that depends on Urbit authentication right now, unless you put your +code into it as-is.

Most common way this is solved seems to be API keys of various sorts. What I imagine we ultimately want (though opinions may vary on this) is an access token mechanism, which you can give out to individual clients, and revoke as desired. Further down the line you'll want to augment these with more fine-grained permission management, ie "chat only" or "read only" or w/e, and some logging for their usage.

This feels like it's not actually too far off what you're proposing, and might just be the other side of the protocol|backend coin.

Putting the burden for all of that entirely on Eyre feels not entirely correct to me though. It's already not the simplest vane. There's interesting options here wrt pretending that outside callers are moons or comets, which would integrate much more readily with existing systems, even if still a little underbaked.


Tyler Shuster

Oct 9, 2020, 1:32:21 PMOct 9
to Mark, urbit-dev
Yes, throwing no shade. Just ruminating about how to improve based on lessons learned.

That’s a good point about cookies expiring. I was thinking of just putting +code in, but yeah, that could be bad.

API keys do seem like the way to go — do cookies expire in Eyre or is it just the MaxAge header? If the latter, the JSON I was proposing would work.

The fine-grained permissions seems desirable, but that certainly seems outside the realm of Eyre, poor overworked thing. Integrating it into the moon use case seems intriguing and helps to advance that one as well.


Oct 9, 2020, 1:45:24 PMOct 9
to Tyler Shuster, urbit-dev
> do cookies expire in Eyre or is it just the MaxAge header?

Cookies match a session that's stored in Eyre, and expires there too.

I forgot, but am now reminded, that we changed sessions (and their cookies) to extend-on-use a little while ago, to solve the "silently logged out of landscape" case. So, the cookie sessions are fine as long as you're using them at least once a week... but imo that's not quite sufficient.

Reply all
Reply to author
0 new messages