Hi sandstorm-dev and Jas,
Here's how I'm thinking of allowing Sandstorm apps to expose HTTP APIs:
- All requests must have an HTTP "Authorization" header in OAuth 2 bearer token style:
Authorization: Bearer 0cIFXMm47dDPZNSjVSAZEQqvyXo
- The bearer token actually not only proves authorization, but also identifies the specific grain (app instance) to which the request is addressed. This makes it not just a token, but a capability.
- Notice that it's thus not possible to open an API directly in a browser tab, because the browser will not send the "Authorization" header. This is by design: By ensuring that resources served from an API cannot be opened in a browser context, we close a large number of possible security issues. For instance, we ensure that no app can cause arbitrary code to execute in the API's origin, which makes it safe for all APIs to share an origin. (It's also important that API endpoints cannot be used in e.g. <object> tags, as this would allow an app to do all kinds of bad things by serving a malicious Flash file.)
- That said, XmlHTTPRequests will have no problem adding the appropriate header, so APIs can be accessed in the browser through appropriate Javascript.
- The standard way to designate an API capability in text will be to form a URL by taking the API origin, appending a '#', and then appending the capability token. If such a URL is literally opened in a browser, we can potentially present the user with an "API explorer" interface which allows them to poke at the API. The access key will be embedded in the fragment (the # part), which has the nice property that browsers will never include it in a "Referrer" header. (We should probably do this with grain URLs too.)
- APIs will always be served with "Access-Control-Allow-Origin: *" so that they can be invoked from anywhere (provide you have the right capability token).
- An app will be able to ask Sandstorm to create new API token pointing back at it. The app can then present an API URL to the user, and the user can copy/paste that URL into some app (e.g. a mobile client) that wants to connect to the API.
- If you want an API to be public, it is perfectly valid to simply publish the token. You might even embed it in a web site's Javascript to create a site that interacts with your API (e.g. this could be used to implement comments in a blogging app).
- For now, API requests will be delivered by opening another special kind of session, HackApiSession. sandstorm-http-bridge will be configurable to forward these requests to the app with a specified host header and path prefix. In the future, APIs will be exposed by implementing some "HttpApi" interface and publishing it to the Powerbox.
- Eventually, Sandstorm's frontend will support incoming OAuth so that you can initiate a request to access the user's stuff externally. The OAuth flow will in fact invoke the Powerbox. Notice that existing OAuth clients may "just work" with the Powerbox and capabilities even though they weren't designed to work with them, since Sandstorm will just return them a capability that they use like a regular OAuth access token.
Thoughts?
Unfortunately, many client apps may need minor tweaking to work with Sandstorm APIs. Many apps have hand-rolled authentication in their APIs, e.g. passing usernames and passwords, which obviously doesn't work with Sandstorm. Instead, such apps will need to learn how to accept and use a bearer token, which is probably a minor tweak in most cases. Apps that are already based on OAuth 2 will have an easier time, although until we actually have the OAuth UI implemented, these apps will need to provide some way to specify a URL and access token manually. Some may have this already, but many won't.
-Kenton