Skip to content

Instantly share code, notes, and snippets.

@brianloveswords
Last active December 13, 2015 19:29
Show Gist options
  • Save brianloveswords/4963040 to your computer and use it in GitHub Desktop.
Save brianloveswords/4963040 to your computer and use it in GitHub Desktop.

Resource/API discovery: specified, .well-known, or <link>?

Problem Statements

Generic

There are various ServiceProviders that do X, Y, and/or Z. A valid SP must do X and Y, but Z is optional. A user generally picks one SP (or hosts their own) and uses that exclusively. The SP needs to provide authenticated API endpoints for each of the actions it provides, e.g. GET /api/x, POST /api/y.

An Application needs to interact with a user's SP. Discovery of the user's SP happens via WebFinger or some intermediary (e.g., explicitly asking the user and storing preference, like http://www.subtome.com/? Any other suggestions?).

Once the user's SP has been determined, the Application needs to know how to communicate with the SP (without going through the intermediary) and what methods are supported. What is the best way for an application to figure out the supported API endpoints of a ServiceProvider?

Specific

I am working on federation for "OpenBadge Backpacks". I want users to be able to host their backpack anywhere and to have issuers be able to interact with a user's specified backpack using a generic interface (rather than having issuers figure out/dictate/hardcode which backpacks they support).

Ideally a user should be able to say to the issuer "My backpack is at https://example.org" (or predefine this so it's somehow discoverable) and the issuer should be able to communicate with that backpack without having to apply conditional logic specific to example.org.

Solution 1: Completely Specified Endpoints

The specification for ServiceProviders could say "You MUST have your API endpoints at /api/x, /api/y and /api/y". Applications/libraries would hardcode relative paths and route actions to the ServiceProviders based on <origin>+<relative path for action>.

Potential Issues

  • This seems too restrictive for ServiceProviders. I could see an SP wanting the flexibility to choose their API root.
  • Capabilities would have to be figured out by trial & error.

Solution 2: Descriptive File + <link>

The specification could require an description file, e.g.

{
  "name" "Example ServiceProvider",
  "apiRoot": "https://api.example.org",
  "capabilities": ["x", "y"]
}

The descriptive file should be discoverable by scanning for a <link rel="serviceprovider:api" href="<path-to-resource>"> and have that file be somewhere in the HTTP response to

GET / HTTP/1.1
Host: example.org

Potential issues

  • What's the appropriate rel for this?
  • Requires the Application to parse HTML (though they could "cheat" with a regexp)

Solution 3: Descriptive File + .well-known

Same descriptive file as above, but the location would be standardized at a .well-known/ location (see RFC 5758).

Potential Issues

  • Appendix B of RFC 5758 claims that well-known locations are "bad for the web" and I don't know why.

"Why do we need ServiceProviders? Can't we just use local storage?"

Local storage should be an option, but for my specific use case we need hosted providers. Many of our users access the internet mainly through public terminals, so we can't guarantee data integrity between sessions.

Anything else?

I'm open to entirely different suggestions of how to solve this problem. I'm partial to the idea of a "descriptive file" that states a ServiceProvider's capabilities becasue I think it's nicely extensible.

There's also an inherent assumption that the API root is the only potential difference between ServiceProviders, and that everything below that is uniform. I think it's acceptable to specify this, mainly because I think not doing that would increase complication be an unacceptable amount, but I'm open to discussion on that front as well.

@brianloveswords
Copy link
Author

@djc, the way I'm imagining it, backpack locations would be based on subdomain. http://example.org and http://hey.example.org could point to two different backpacks, but https://example.org/path/to/something would still be the backpack at http://example.org.

@lmorchard
Copy link

Oh, and re: RFC 5785, Appendix B, "Aren't well-known locations bad for the Web?"

I think the bad mostly consists of:

  • URLs should ideally be considered opaque identifiers, leaving URL-space control in the hands of whomever owns the URLs & runs the services.
  • If you don't control the root URL-space of your domain, you can't play with .well-known. That's a consequence of giving up URL opacity, but it's a usability tradeoff for discovery without asking users to carry URLs around.
  • That RFC 5785 sticks a stake in the ground with .well-known means that it at least doesn't infect the rest of your URL-space. (ie. that's the "sandbox" part)

That's why I say I'm lazy when I like Solution 1. I can think less about flexibility and make more demands on service providers' URL-space, but that's rather rude.

@lmorchard
Copy link

Requiring different subdomains makes me grumble a bit, just as it has with Open Web Apps and BrowserID and a few other things. But, the origin-based security model just makes all those things dovetail more nicely than just about anything else. Mostly, it's a hosting thing (ie. subdomains + SSL has gotchas)

@stenington
Copy link

RegisterProtocolHandler registers the selected handlers in the browser, doesn't it? I think that breaks down for some of our users as mentioned in the "Can't we just use localStorage" section. I'm not clear on how the Web Intents shim does it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment