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?
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
.
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>
.
- 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.
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
- What's the appropriate
rel
for this? - Requires the Application to parse HTML (though they could "cheat" with a regexp)
Same descriptive file as above, but the location would be standardized at a .well-known/
location (see RFC 5758).
- Appendix B of RFC 5758 claims that well-known locations are "bad for the web" and I don't know why.
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.
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.
As I understand it, Persona / BrowserID has an interesting path to this - at least with respect to the Issuing API:
Require developers to use a common JS bootstrap from login.persona.org, which instantiates an API.
The bootstrap + login.persona.org service uses the user's proposed identity (ie. email address) to delegate to their chosen ID provider, detected using
https://{email-domain}/.well-known/browserid
.This could be done using webfinger. I think BrowserID went a different route so they could extend their own format.
The browser (or an addon) can inject the API itself, in which case the common bootstrap include knows to step out of the way. This is a progressive upgrade from the potential single-point-of-failure presented by the bootstrap shim.
The browser-injected API can be loaded from the chosen ID provider directly. No delegation, in this case.
This isn't perfect, because the bootstrap is still a single-point-of-failure. But, it makes things easier on developers, so they don't have to worry about service discovery themselves. In other words, if OpenBadges followed this pattern, a user would never have to tell an Issuer what backpack he or she uses. The user would only have to tell openbadges.org or his/her browser (or addon) what backpack to use.
Seems like Web Intents could be interesting too: Install an app, and that app declares the service provider for an action (ie. accepting badges). That could basically take the place of the addon. I wonder if there's a cross-browser way to make that mesh with all the above?
And of course, none of the browser/addon stuff helps the Displayer API, where the displaying site has to use the bootstrap because User A viewing User B's badges can't offer any clue as to where the backpack for User B is. But, getting at the Displayer API feels like a different problem to me than getting badges from random sites routed to the right backpack. But, using something like
.well-known
or webfinger for service discovery can help there, too. (Solution 3?)