Files
hzrd149 5d92ee621f Make HTTP great again
Add specific status codes to endpoints for clarity
2026-04-06 11:18:28 -05:00

92 lines
5.7 KiB
Markdown

# BUD-11
## Nostr Authorization
`draft` `optional`
Defines the format of the authorization token used by Blossom servers to identify users and by users to authorize actions on those servers. Authorization tokens are optional; servers MAY require them for specific endpoints.
## Authorization tokens
Authorization tokens are signed [nostr](https://github.com/nostr-protocol/nips/blob/master/01.md) events of kind `24242` proving to a server that the user (`pubkey`) has permitted an application to take an action on their behalf.
All authorization tokens:
- MUST have the `content` set to a human readable string explaining intended use to the user. For example `Upload Blob`, `Delete old blobs`, `List Images`, etc.
- MUST have a [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) `expiration` tag set to a unix timestamp at which the token should be considered expired.
- MUST have a `t` tag with a verb of `get`, `upload`, `list`, `delete`, or `media`. The value of the `t` tag MUST correspond to the action performed by the target endpoint, as defined in the section [Endpoint Authorization Requirements](#endpoint-authorization-requirements).
## Tag scoping
Authorization tokens MAY include `server` and `x` tags to scope the token to specific servers or blob hashes.
- **`server` tag**: Limits the token to specific servers by domain name. If no `server` tags are present, the token is valid for all servers. Multiple `server` tags may be present to allow the token to be used on multiple servers. The value MUST be a lowercase domain name only (e.g., `cdn.example.com`), not a full URL.
- **`x` tag**: Scopes the token to specific lowercase hex-encoded blob hashes. Multiple `x` tags may be present for endpoints that require a sha256 hash. When `x` tags are present, the token is only valid for operations on the specified blob hashes.
Example authorization token:
```jsonc
{
"id": "7a1735c3852cf3f374edae4b2af2ee18e750e6dec583e19c4795d3b179af6d17",
"kind": 24242,
"pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"created_at": 1772019044,
"tags": [
["t","upload"],
["expiration","1708858680"],
// Authorization token MAY have multiple "x" tags
["x","b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553"],
],
"content": "",
"sig": "4b57c22b1797b109530ffe5d04cabac468b1a5942873a5141334ecbc77694fc968a1b941979ba13602fceb1dad8014ab6469c6ae9cef0b5668cc23ad1449e103"
}
```
## HTTP Authorization Header
Using the `Authorization` HTTP header, the authorization token MUST be encoded as Base64 URL-safe without padding (Base64url, as used by JWTs) and use the Authorization scheme Nostr
Example HTTP Authorization Header:
```
Authorization: Nostr ewogICJpZCI6ICI3YTE3MzVjMzg1MmNmM2YzNzRlZGFlNGIyYWYyZWUxOGU3NTBlNmRlYzU4M2UxOWM0Nzk1ZDNiMTc5YWY2ZDE3IiwKICAia2luZCI6IDI0MjQyLAogICJwdWJrZXkiOiAiNzliZTY2N2VmOWRjYmJhYzU1YTA2Mjk1Y2U4NzBiMDcwMjliZmNkYjJkY2UyOGQ5NTlmMjgxNWIxNmY4MTc5OCIsCiAgImNyZWF0ZWRfYXQiOiAxNzcyMDE5MDQ0LAogICJ0YWdzIjogWwogICAgWyJ0IiwidXBsb2FkIl0sCiAgICBbImV4cGlyYXRpb24iLCIxNzA4ODU4NjgwIl0sCiAgICAvLyBBdXRob3JpemF0aW9uIHRva2VuIE1BWSBoYXZlIG11bHRpcGxlICJ4IiB0YWdzCiAgICBbIngiLCJiMTY3NDE5MWE4OGVjNWNkZDczM2U0MjQwYTgxODAzMTA1ZGM0MTJkNmM2NzA4ZDUzYWI5NGZjMjQ4ZjRmNTUzIl0sCiAgXSwKICAiY29udGVudCI6ICIiLAogICJzaWciOiAiNGI1N2MyMmIxNzk3YjEwOTUzMGZmZTVkMDRjYWJhYzQ2OGIxYTU5NDI4NzNhNTE0MTMzNGVjYmM3NzY5NGZjOTY4YTFiOTQxOTc5YmExMzYwMmZjZWIxZGFkODAxNGFiNjQ2OWM2YWU5Y2VmMGI1NjY4Y2MyM2FkMTQ0OWUxMDMiCn0
```
## Validation
To validate an authorization token, a server MUST perform the following checks:
1. The event `kind` MUST be `24242`.
2. The `created_at` timestamp MUST be in the past.
3. An `expiration` tag MUST be present and set to a Unix timestamp in the future.
4. The `t` tag MUST contain a verb matching the intended action of the endpoint.
5. If one or more `server` tags are present, the server MUST verify that its domain name appears in at least one `server` tag.
6. If the endpoint requires `x` tags, the server MUST verify that at least one `x` tag matches the blob hash implied by the endpoint.
## Endpoint Authorization Requirements
The table below defines, for each endpoint, the required `t` tag action, the implied blob hash (if any), and whether at least one matching `x` tag is required.
| Endpoint | Required `t` | Implied Blob Hash | `x` Tag Requirement |
| -------------------- | ------------ | ---------------------------- | ------------------- |
| `GET /<sha256>` | `get` | `<sha256>` from the URL | optional |
| `HEAD /<sha256>` | `get` | `<sha256>` from the URL | optional |
| `PUT /upload` | `upload` | `X-SHA-256` request header | required |
| `HEAD /upload` | `upload` | `X-SHA-256` request header | required |
| `DELETE /<sha256>` | `delete` | `<sha256>` from the URL | required |
| `GET /list/<pubkey>` | `list` | — | not applicable |
| `PUT /mirror` | `upload` | SHA-256 of the mirrored blob | required |
| `PUT /media` | `media` | `X-SHA-256` request header | required |
| `HEAD /media` | `media` | `X-SHA-256` request header | required |
## Security Considerations
### Unscoped Tokens
A token that does not include a `server` tag is valid on any Blossom server that accepts it. If intercepted or leaked, such a token can be replayed against other servers for the duration of its validity (until its `expiration`).
This risk is particularly significant for `delete` tokens. An unscoped `delete` token intercepted from one server can be reused to delete the same blob from any other server where it exists.