Skip to content
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Build Status GoDoc


An opaque object storage service.

oostore is designed for sharing small amounts of content. In exchange for posted content, oostore responds with a macaroon that may be used to retrieve or delete the content.

Caveats may then be added to this macaroon -- which can place all sorts of conditions on its validity. Just about any kind of authorization policy imaginable should be possible to implement, by adding caveats to opaque content macaroons.

Macaroons? What?

For more background on what macaroons are all about and why you might want to use them, I recommend:

First-party caveats currently understood by this service:

object object-id

Request must operate on this object. oostore will currently add this caveat automatically when a new object is created and a macaroon is issued, in response so that the creator can manage it, and distribute authorization to others.

time-before RFC3339-timestamp

Authorization expires after a set time. The timestamp is compared against current time on the oostore server. This caveat is provided by the macaroon-bakery.

client-ip-addr w.x.y.z

Only client requests from a specific IP address are allowed. This caveat is provided by the macaroon-bakery.

Stay tuned as oostore will become much more interesting (and useful, and secure) once third-party caveats can be added against discharging services designed for use with oostore.


Macaroons are given in response to resource creation, and then sent as request content for authorization. I feel like this is somewhat unorthodox for a web API (usually you'd use cookies, and a 401 challenge-response) but for this use case, it seemed appropriate. Plus, cookies have limitations on size, domains, etc.

Support for authentication with cookies may be added on later to enable simple web clients like browsers, etc. for specific use cases.


Create a new object.


  • [Header] Content-Type: Will be stored with opaque object, preserved on retrieval. Defaults to application/octet-stream
  • [Contents] opaque object bytes

Response 200 OK

  • [Header] Location: Path of newly created object.
  • [Header] Content-Type: application/json
  • [Contents] The JSON-encoded macaroon, which is your authorization token for the object.


$ curl -i -X POST --data "good things" http://localhost:20080
HTTP/1.1 200 OK
Location: /7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj
Date: Sat, 19 Sep 2015 04:31:52 GMT
Content-Length: 235
Content-Type: text/plain; charset=utf-8

[{"caveats":[{"cid":"object 7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj"}],"location":"","identifier":"76d828f7ae2e3a079c906994304144603cdb6a96d60ef112","signature":"30f1c4c87589e090150912a5b1c13c319c9a7f01100a9c077a14854ff5d3fc4a"}]

POST /:object

Retrieve an object.


  • [Path] Location of object given in prior POST. Note that this can also be derived from the "object" caveat in the macaroon.
  • [Contents] The JSON-encoded macaroon, which is your authorization token for retrieval.

Response 200 OK

  • [Header] Content-Type: Same content type specified when object was created.
  • [Contents] Object contents.


$ curl -X POST --data @/dev/stdin http://localhost:20080/7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj <<EOF
> [{"caveats":[{"cid":"object 7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj"}],"location":"","identifier":"76d828f7ae2e3a079c906994304144603cdb6a96d60ef112","signature":"30f1c4c87589e090150912a5b1c13c319c9a7f01100a9c077a14854ff5d3fc4a"}]
good things$ 

DELETE /:object

Delete an object.


  • [Path] Location of object given in prior POST. Note that this can also be derived from the "object" caveat in the macaroon.
  • [Contents] The JSON-encoded macaroon, which is your authorization token for deleting the object.

Response 204 No Content


$ curl -i -X DELETE --data @/dev/stdin http://localhost:20080/7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj <<EOF
[{"caveats":[{"cid":"object 7zCHWLjyMohzSrKUHRg2wLMb4hvPkV7mdEeDbweAhJZj"}],"location":"","identifier":"76d828f7ae2e3a079c906994304144603cdb6a96d60ef11
HTTP/1.1 204 No Content
Date: Sat, 19 Sep 2015 04:44:36 GMT


I recommend using a separate GOPATH for every project, to avoid overlapping dependency conflicts.

Get the source & deps with go get

In $GOPATH/src/, run tests with go test.

Install the oostore binary into $GOPATH/bin with go get


Copyright 2015 Casey Marshall.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


An opaque object store featuring decentralized authorization with macaroons.




No releases published


No packages published