Contents
The Macaroon API provides means to request and verify macaroons that can be used to authenticate requests against the Store.
The Macaroon API is exposed at the following base URLs:
JSON will be returned in all responses from the API, including errors.
The Macaroon API uses conventional HTTP response codes to indicate success or failure of an API request. In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that resulted from the provided information (e.g. a required parameter was missing) and codes in the 5xx range indicate an error with our servers.
Error responses will be structured according to the Problem Details for HTTP APIs specification.
In summary this means that they will include the following fields in the body:
| type: | string A URI reference [RFC3986] that identifies the problem type. |
|---|---|
| title: | string A short, human-readable summary of the problem type. |
| detail: | string An human readable explanation specific to this occurrence of the problem. |
| status: | number The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem. |
Example
{
"type": "devportal:v1:request-invalid",
"title": "Invalid request.",
"detail": "Expected permissions to be a list. Got: package_access",
"status": 400
}
POST /dev/api/acl/¶| Request JSON Object: | |
|---|---|
|
|
| Response JSON Object: | |
|
|
| Status Codes: |
|
The current values are valid permissions
edit_accountpackage_accesspackage_managepackage_uploadpackage_upload_requestpackage_purchasemodify_account_keyWhen specifying a list of packages to restrict the macaroon, those can be indicated in two ways:
{"name": "the-name", "series": "16"}{"snap_id": "some-snap-id-1234"}This endpoint is normally used without authentication, and returns a
macaroon with a third-party caveat requiring a discharge from SSO.
However, when requesting a package_upload macaroon, a discharged
package_upload_request macaroon may be supplied as authorization for the
request; in that case, that is taken as authorization to issue
package_upload macaroons with more specific constraints that do not
require a discharge from SSO.
Request a macaroon for editing an account.
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["edit_account"],
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
Request a generic macaroon for retrieving package metadata.
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["package_access"],
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
Request a macaroon for managing a specific package
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["package_manage"],
"packages": [{"snap_id": "foo-id-1234"}]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
Request a macaroon for uploading a specific package
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["package_upload"],
"packages": [{"name": "foo", "series": "16"}]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
Request a macaroon for purchasing a package identified by snap_id
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["package_purchase"],
"packages": [{"snap_id": "foo-id-1234"}]
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
Request a macaroon for modifying account keys.
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["modify_account_key"],
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"macaroon": "the-serialized-macaroon-data"
}
If the request was made for an invalid permission to be included, the server will respond with something like
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": ["package_delete"],
}
Response:
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json; charset=utf-8
{
"type": "devportal:v1:macaroon-permission-invalid",
"title": "Invalid permission for macaroon.",
"detail": "Permission is not valid: package_delete",
"status": 400,
"permission": "package_delete"
}
If the request is invalid in some other way, the server will respond accordingly. For example
Request:
POST /dev/api/acl/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"permissions": "package_access",
}
Response:
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json; charset=utf-8
{
"type": "devportal:v1:request-invalid",
"title": "Invalid request.",
"detail": "Expected permissions to be a list. Got: package_access",
"status": 400,
}
If a macaroon was requested for a particular package that doesn’t exist, the server will respond with a generic 404 response.
Response:
HTTP/1.1 404 NOT FOUND
POST /dev/api/acl/verify/¶| Request JSON Object: | |
|---|---|
|
|
| Response JSON Object: | |
|
|
| Status Codes: |
|
The auth_data object should contain:
http_uri: the full URI of the request being verifiedhttp_method: the http method used for the request being verifiedauthorization: the value of the Authorization header of the request being verifiedThe account data, if not null will be a json object containing the fields:
email: the primary email of the accountdisplayname: the name used to identify the accountopenid: the openid identifier for the accountverified: whether the account has been verifiedSubmit the request to verify a macaroon used for authorization.
Request
POST /dev/api/acl/verify/ HTTP/1.1
Host: myapps.developer.ubuntu.com
Content-Type: application/json
{
"auth_data": {
"http_uri": "http://example.org",
"http_method": "POST",
"authorization": "Macaroon root=root-macaroon-data, discharge=discharge-macaroon-data"
}
}
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"allowed": true,
"refresh_required": false,
"account": {
"email": "user@example.org",
"displayname": "The User",
"openid": "oid1234",
"verified": true
},
"last_auth": "2016-05-26T12:53:23Z",
"permissions": ["package_access"]
}
If the macaroon was expired the following response would be returned instead
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"allowed": false,
"refresh_required": true,
"account": null,
"last_auth": null,
"permissions": null,
}
Alternatively, if the macaroon was invalid in any way, the server would reply with
Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"allowed": false,
"refresh_required": false,
"account": null,
"last_auth": null,
"permissions": null,
}
In case the original request was invalid, for example if the auth_data parameter was missed, the server would return the following response
Response:
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json; charset=utf-8
{
"type": "devportal:v1:request-invalid",
"title": "Invalid request.",
"detail": "Missing expected \"auth_data\" parameter.",
"status": 400
}