Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4745379
appnote: Add appnote covering Authorisation
samdbmg Feb 13, 2025
03f6d25
appnote: Add AuthZ tags to tag list
samdbmg Feb 14, 2025
dd9c8d6
Enumerate endpoints, methods, and recommended roles for coarse-grain …
j616 Jun 30, 2025
f52328a
Enumerate endpoints, methods, and recommended auth logic for fine-gra…
j616 Jul 2, 2025
ff63855
Remove ❌ emoji from coarse-grain auth table
j616 Jul 2, 2025
b9845ae
Update tag listing
j616 Jul 2, 2025
6344f9e
Align coarse-grain logic with fine-grain
j616 Jul 8, 2025
c134c6d
Improve split of auth logic, implementation details, and use cases
j616 Jul 8, 2025
8426e89
Be explicit on returning 404 for objects which are not yet in use
j616 Jul 8, 2025
244418c
Rename `scopes` to `auth_classes`
j616 Jul 8, 2025
9744aad
Rename `scope` to `auth_classes` in tag listing
j616 Jul 8, 2025
c3ab6a9
Add support for lists as tag values
j616 Jul 8, 2025
a8c2d2e
Add flow tag filters to objects endpoint
j616 Jul 8, 2025
e7eef52
Fix linting
j616 Jul 8, 2025
db82fcb
Add tags to webhooks
j616 Jul 8, 2025
2ce7d42
Improve fine-grained webhook documentation
j616 Jul 9, 2025
bd508f0
Add ADR on fine-grained auth
j616 Jul 10, 2025
0d6aef9
Change based on feedback
j616 Jul 10, 2025
a2f3646
Various tweaks
j616 Jul 11, 2025
5a1c267
Add info on "deny" permissions. Expand explanation of permissions pro…
j616 Jul 11, 2025
67bfbbc
Add regex to tag query strings
j616 Jul 11, 2025
e99ae21
Apply suggestions from code review
j616 Jul 11, 2025
fd1cb4e
Changes following review
j616 Jul 11, 2025
42f90a7
Add (rejected) option to ADR0035 on mandating proposed fine-grained a…
j616 Jul 11, 2025
9cedde5
adr: Minor wording improvement on authz
samdbmg Jul 30, 2025
7d3fe31
appnote: Mention request context in authz
samdbmg Jul 30, 2025
555f0dd
Add missing note to 404 on objects endpoint GET
j616 Aug 19, 2025
896c00a
Fix typo
j616 Aug 19, 2025
5db39a0
Fixed typo in description of how to determine object permissions
j616 Sep 24, 2025
3bffae8
Add new webhook and objects endpoints
j616 Sep 24, 2025
1da95e7
Tweak webhooks permissions following feedback, and to better represen…
j616 Sep 24, 2025
a246d95
Use style introduced in recent docs audit
j616 Sep 24, 2025
01f2140
Require read permissions on sources & flows when editing webhook filters
j616 Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 15 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,30 +175,7 @@ This is intended to reduce the amount of polling required by clients to keep up
However the specification is deliberately left open-ended; only the message bodies are specified, but not the protocol by which they are carried nor the method by which clients subscribe.
It is assumed that implementations will provide a suitable mechanism, such as a call to allow clients to subscribe to webhooks, or details of an event bus to connect to and receive the messages.

### Security

The TAMS specification stipulates authentication methods that a client should support in order to identify themselves and provide credentials to the server, using standard HTTP approaches.
The authorisation model (the rules by which authenticated requests are allowed or denied) is not part of the TAMS specification, and is up to individual implementers and organisations depending on their exact rules, needs and threat model.

It is assumed that implementations will apply other IT and cloud infrastructure security best practices, notably including the use of TLS (e.g. HTTPS connections) within and between their systems.

## Mock TAMS Service

This repo contains some automation to run a mock version of the API using [Stoplight Prism](https://stoplight.io/open-source/prism).
To run the mock server using Docker, try something like the command below (or run `make mock-server-up`):

```shell
docker run --rm --init --name mock-tams -v "$(pwd)":/data:ro -p 4010:4010 stoplight/prism mock /data/TimeAddressableMediaStore.yaml -h 0.0.0.0
```

A mock API server will start at <http://localhost:4010>

## Proposals, Decisions and Architecture Changes

This repository uses [(M)ADR documents](https://adr.github.io/madr/) to propose significant changes, facilitate discussions and decision making, and to store a record of options that were considered.
These documents may be found in the [docs/adr](./docs/adr/) directory, and are managed as described by the [ADR Readme](./docs/adr/README.md).

## API Versioning
### API Versioning

The API is versioned using a major and minor version number.
A breaking change - such as removal of a feature, or renaming of properties in such a way that would break compatibility (including fixing a typo) - results in a major version increment and the minor version is reset to 0.
Expand All @@ -218,7 +195,20 @@ Otherwise, the version will not change.

It is possible to see what the version would be if a release was made at the current commit by running `make next-version` in the top directory of this repository.

### Making a release
### Security

The TAMS specification stipulates authentication methods that a client should support in order to identify themselves and provide credentials to the server, using standard HTTP approaches.
The authorisation model (the rules by which authenticated requests are allowed or denied) is not part of the TAMS specification, and is up to individual implementers and organisations depending on their exact rules, needs and threat model.
However some principles and suggestions are discussed in [AppNote0016: Authorisation in TAMS workflows](./docs/appnotes/0016-authorisation-in-tams-workflows.md).

It is assumed that implementations will apply other IT and cloud infrastructure security best practices, notably including the use of TLS (e.g. HTTPS connections) within and between their systems.

## Proposals, Decisions and Architecture Changes

This repository uses [(M)ADR documents](https://adr.github.io/madr/) to propose significant changes, facilitate discussions and decision making, and to store a record of options that were considered.
These documents may be found in the [docs/adr](./docs/adr/) directory, and are managed as described by the [ADR Readme](./docs/adr/README.md).

## Making a release

Run the `release` workflow under the `Actions` tab on this repository on GitHub against the `main` branch.
This workflow requires approval.
Expand Down
108 changes: 92 additions & 16 deletions api/TimeAddressableMediaStore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,26 @@ paths:
tags:
- Webhooks
parameters:
- name: tag.{name}
in: query
description: |
Filter on webhooks that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} could contain escaped characters to allow it to be used in a URL.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Filter on webhooks that have a tag named {name} regardless of value.
The {name} could contain escaped characters to allow it to be used in a URL.
If set to true then the presence of the tag is filtered for.
If set to false then its absence is.
If left out then no filtering on tag presence is performed.
schema:
type: boolean
- $ref: '#/components/parameters/trait_resource_paged_key'
- $ref: '#/components/parameters/trait_paged_limit'
responses:
Expand Down Expand Up @@ -188,6 +208,26 @@ paths:
tags:
- Webhooks
parameters:
- name: tag.{name}
in: query
description: |
Filter on webhooks that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} could contain escaped characters to allow it to be used in a URL.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Filter on webhooks that have a tag named {name} regardless of value.
The {name} could contain escaped characters to allow it to be used in a URL.
If set to true then the presence of the tag is filtered for.
If set to false then its absence is.
If left out then no filtering on tag presence is performed.
schema:
type: boolean
- $ref: '#/components/parameters/trait_resource_paged_key'
- $ref: '#/components/parameters/trait_paged_limit'
responses:
Expand Down Expand Up @@ -370,10 +410,13 @@ paths:
- name: tag.{name}
in: query
description: |
Filter on Sources that have a tag named {name} and with the given value.
{name} and the value MUST be URL encoded where special characters are present.
Filter on Sources that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} and the value MUST be URL encoded where special characters are present.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
type: string
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Expand Down Expand Up @@ -428,10 +471,13 @@ paths:
- name: tag.{name}
in: query
description: |
Filter on Sources that have a tag named {name} and with the given value.
{name} and the value MUST be URL encoded where special characters are present.
Filter on Sources that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} and the value MUST be URL encoded where special characters are present.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
type: string
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Expand Down Expand Up @@ -814,10 +860,13 @@ paths:
- name: tag.{name}
in: query
description: |
Filter on Flows that have a tag named {name} and with the given value.
{name} and the value MUST be URL encoded where special characters are present.
Filter on flows that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} and the value MUST be URL encoded where special characters are present.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
type: string
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Expand Down Expand Up @@ -898,10 +947,13 @@ paths:
- name: tag.{name}
in: query
description: |
Filter on Flows that have a tag named {name} and with the given value.
{name} and the value MUST be URL encoded where special characters are present.
Filter on flows that have a tag named {name} with a value in the given comma-seperated list of values.
The {name} and the value MUST be URL encoded where special characters are present.
Where the tag's value is a string, at least one of the given values will match.
Where the tag's value is an array, at least one value in the array will match at least one of the given values.
Partial string matches of the values are not valid.
schema:
type: string
$ref: 'schemas/url-tag-list.json'
- name: tag_exists.{name}
in: query
description: |
Expand Down Expand Up @@ -2152,6 +2204,18 @@ paths:
Where multiple filter query parameters are provided, the returned `get_urls` will match all filters.
schema:
type: boolean
- name: flow_tag.{name}
in: query
description: |
Filter `referenced_by_flows` on tag values. This option is the same as the `tag.{name}` query parameter on the `/flows/` API endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My gut feeling is that this should also "filter" the flow id from the first_referenced_by_flow field in the same way. Otherwise if we are using this tag query parameter to provide an early implementation of RBAC/ABAC we would be removing a flow id from referenced_by_flows only to leave it visible in first_referenced_by_fMy gut feeling is that this should also "filter" the flow id from the first_referenced_by_flow field in the same way. Otherwise if we are using this tag query parameter to provide an early implementation of RBAC/ABAC we would be removing a flow id from referenced_by_flowsonly to leave it visible infirst_referenced_by_flow. Just a thought and i'm not "wedded to it".low. Just a thought and i'm not "wedded to it".

Copy link
Contributor

@j616 j616 Sep 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right. But I think what we choose to do here may be affected by the discussion on whether we are happy to elevate auth classes strait to the core spec. So I'll hold off on this change for now.

schema:
type: string
- name: flow_tag_exists.{name}
in: query
description: |
Filter `referenced_by_flows` on tag names. This option is the same as the `tag_exists.{name}` query parameter on the `/flows/` API endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per comment above about also filtering first_referenced_by_flow.

schema:
type: boolean
- $ref: '#/components/parameters/trait_resource_paged_key'
- $ref: '#/components/parameters/trait_paged_limit'
responses:
Expand All @@ -2177,7 +2241,7 @@ paths:
"400":
$ref: '#/components/responses/trait_resource_info_head_400'
"404":
description: The requested Media Object does not exist.
description: The requested Media Object does not exist. 404 MUST be returned if the ID has been assigned via the [`/flows/{flowId}/storage`](#/operations/POST_flows-flowId-storage), but not yet registered against a Flow Segment.
get:
summary: Media Object Information
description: |
Expand Down Expand Up @@ -2237,6 +2301,18 @@ paths:
Where multiple filter query parameters are provided, the returned `get_urls` will match all filters.
schema:
type: boolean
- name: flow_tag.{name}
in: query
description: |
Filter `referenced_by_flows` on tag values. This option is the same as the `tag.{name}` query parameter on the `/flows/` API endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per comment above about also filtering first_referenced_by_flow.

schema:
type: string
- name: flow_tag_exists.{name}
in: query
description: |
Filter `referenced_by_flows` on tag names. This option is the same as the `tag_exists.{name}` query parameter on the `/flows/` API endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per comment above about also filtering first_referenced_by_flow.

schema:
type: boolean
- $ref: '#/components/parameters/trait_resource_paged_key'
- $ref: '#/components/parameters/trait_paged_limit'
responses:
Expand Down Expand Up @@ -2264,7 +2340,7 @@ paths:
"400":
description: Bad request. Invalid query options.
"404":
description: The requested media object does not exist.
description: The requested media object does not exist. 404 MUST be returned if the ID has been assigned via the [`/flows/{flowId}/storage`](#/operations/POST_flows-flowId-storage), but not yet registered against a Flow Segment.
/objects/{objectId}/instances:
post:
summary: Register a Media Object instance
Expand Down Expand Up @@ -2315,7 +2391,7 @@ paths:
"403":
description: Forbidden. You do not have permission to modify this Media Object.
"404":
description: The Media Object does not exist.
description: The Media Object does not exist. 404 MUST be returned if the ID has been assigned via the [`/flows/{flowId}/storage`](#/operations/POST_flows-flowId-storage), but not yet registered against a Flow Segment.
delete:
summary: Delete a Media Object instance
description: |
Expand Down Expand Up @@ -2354,7 +2430,7 @@ paths:
"403":
description: Forbidden. You do not have permission to modify this Media Object.
"404":
description: The requested Object ID in the path is invalid.
description: The requested Object ID in the path is invalid. 404 MUST be returned if the ID has been assigned via the [`/flows/{flowId}/storage`](#/operations/POST_flows-flowId-storage), but not yet registered against a Flow Segment.

/flow-delete-requests:
head:
Expand Down
14 changes: 12 additions & 2 deletions api/schemas/tags.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
{
"title": "Tags",
"description": "Key value is a freeform string.",
"description": "Key is a freeform string. Value is a freeform string, or an array of freeform strings.",
"type": "object",
"additionalProperties": {
"type": "string"
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
}
6 changes: 6 additions & 0 deletions api/schemas/url-tag-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"title": "Query String Tag value list",
"description": "A list of tag values, formatted for use in query string parameters",
"type": "string",
"pattern": "^([^,]+(,[^,]+)*)?$"
}
3 changes: 3 additions & 0 deletions api/schemas/webhook.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
"verbose_storage": {
"description": "Whether to include storage metadata in the `get_urls` property in `flows/segments_added` events. This option is the same as the `verbose_storage` query parameter for the [/flows/{flowId}/segments](#/operations/GET_flows-flowId-segments) API endpoint.",
"type": "boolean"
},
"tags": {
"$ref": "tags.json"
}
}
}
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ For more information on how we use application notes, see [here](./appnotes/READ
| [0013](./appnotes/0013-setting-flow-bit-rate-properties.md) | Setting Flow bit rate properties |
| [0014](./appnotes/0014-referencing-tams-content-in-other-systems.md) | Referencing TAMS content in other systems |
| [0015](./appnotes/0015-using-tams-in-opentimelineio.md) | Using TAMS in OpenTimelineIO |
| [0016](./appnotes/0016-authorisation-in-tams-workflows.md) | Authorisation in TAMS workflows |
| [0017](./appnotes/0017-reuse-of-ids.md) | When to re-use IDs in TAMS and compatible systems |
| [0018](./appnotes/0018-managing-multiple-object-instances.md) | Managing Multiple Object Instances |

Expand Down Expand Up @@ -68,6 +69,7 @@ For more information on how we use ADRs, see [here](./adr/README.md).
| [0031](./adr/0031-flow-image-support.md) | Add new flow type to support still images |
| [0032](./adr/0032-specifying-storage-backend.md) | Specifying storage backend when requesting storage allocation |
| [0034](./adr/0034-storage-allow-object_ids.md) | Add object_ids option to Flow Storage request |
| [0035](./adr/0035-fine-grained-auth.md) | Fine-grained Authorisation in TAMS Workflows |
| [0037](./adr/0037-improve-webhooks.md) | Proposal for improvements to the Webhooks endpoints |
| [0038](./adr/0038-improved-storage-management.md) | Improved Storage Management |
| [0039](./adr/0039-remove-pre-actions.md) | Proposal to remove pre-actions from storage allocation response |
Expand Down
Loading
Loading