diff --git a/Authenticated-Endpoints.md b/Authenticated-Endpoints.md new file mode 100644 index 0000000..f7c7743 --- /dev/null +++ b/Authenticated-Endpoints.md @@ -0,0 +1,418 @@ +All endpoints under namespace `/api/v1/auth` require authentication. + +Authentication can be in one of two forms: + +- A `Cookie: ` header (for logged in users) +- An `Authentication: Bearer ` (recommended) + +A new token can be generated from `/authorize_token` with the given parameters: + +``` +scopes: Comma-separated list of scopes +callback_url: URL to redirect to with generated token +expire: Int64 how long a given token should be valid (in seconds) +``` + +Each `scope` has the following format: + +``` +METHOD1;METHOD2...:ENDPOINT(*)? +``` + +Where `METHOD` can be one of `GET`, `POST`, `PUT`, `DELETE`, `PATCH`. + +An `ENDPOINT` can be any of the documented endpoints below. + +Examples: + +- `POST:playlists*`: authorizes `POST` methods to _any_ endpoint under `/api/v1/auth/playlists` (`/api/v1/auth/playlists`, `/api/v1/playlists/:id/videos`, etc.) + +- `:playlists/*`: authorizes \_any method to endpoints under `/api/v1/auth/playlists/` (`/api/v1/auth/playlists/:id`, `/api/v1/playlists/:id/videos`, etc.) + +- `GET:playlists/IVPAAAAAAA`: authorizes `GET` only to playlist `IVPAAAAAA`. + +- `:preferences`: authorizes _any_ method to `/api/v1/auth/preferences` + +- `GET;POST:preferences`: authorizes `GET` or `POST` to `/api/v1/auth/preferences` + +When a `callback_url` is specified, after a user has authorized a token with the desired `scopes`, a GET request will be made to the `callback_url` with the token URL-escaped and appended as `token=TOKEN`. + +##### GET `/api/v1/auth/feed` + +Get subscription feed for the authenticated user. + +Parameters: + +``` +max_results: Int32 +page: Int32 +``` + +> Schema: + +```javascript +{ + "notifications": [ + { + "type": "shortVideo", + "title": String, + "videoId": String, + "videoThumbnails": [ + { + "quality": String, + "url": String, + "width": Int64, + "height": Int64 + } + ], + "lengthSeconds": Int64, + "author": String, + "authorId": String, + "authorUrl": String, + "published": Int64, + "publishedText": String, + "viewCount": Int64 + } + ], + "videos": [ + { + "type": "shortVideo", + "title": String, + "videoId": String, + "videoThumbnails": [ + { + "quality": String, + "url": String, + "width": Int64, + "height": Int64 + } + ], + "lengthSeconds": Int64, + "author": String, + "authorId": String, + "authorUrl": String, + "published": Int64, + "publishedText": String, + "viewCount": Int64 + } + ] +} +``` + +##### GET `/api/v1/auth/notifications` + +Parameters: + +``` +topics: Array(String) (comma separated: e.g. "UCID1,UCID2) limit of 1000 topics +since: Int64, timestamp +``` + +Provides an [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) for receiving changes from each `topic` in `topics`. Currently the only supported topic-type is `ucid`, which will return an updated video object whenever the given channel uploads a video. + +Important to note is that an event will also be sent when a channel _changes_ an already uploaded video, for example changing description or title. + +Each event is a JSON object with the same schema as `/api/v1/videos`. The `fields` API can be used, which will be applied to each object. + +A `debug` topic can also provided which will return a (psuedo-)randomly selected video every minute. + +`since` will return all videos uploaded since `TIMESTAMP`, with a limit of the 15 most recent videos from each topic. + +More details in [#469](https://github.com/omarroth/invidious/issues/469). + +##### POST `/api/v1/auth/notifications` + +Same as above `GET` endpoint, however `topics` is moved into post body as `Content-Type: application/x-www-form-urlencoded`. + +##### GET `/api/v1/auth/playlists` + +Get list of playlists for the given user. + +> Schema: + +```javascript +[ + { + "type": "invidiousPlaylist", + "title": String, + "playlistId": String, + "author": String, + "authorId": null, + "authorUrl": null, + "authorThumbnails": [], + "description": String, + "descriptionHtml": String, + "videoCount": Int32, + "viewCount": 0, + "updated": Int64, + "isListed": Boolean, + "videos": [ + { + "title": String, + "videoId": String, + "author": String, + "authorId": String, + "authorUrl": String, + "videoThumbnails": [ + { + "quality": String, + "url": String, + "width": Int32, + "height": Int32 + } + ], + "index": Int32, + "indexId": String, + "lengthSeconds": Int32 + } + ] + } +] +``` + +##### POST `/api/v1/auth/playlists` + +`Content-Type: application/json` + +Create new playlist. + +Example request body: + +```javascript +{ + "title": String, + "privacy": "private" +} +``` + +`privacy` can be any of: `public`, `unlisted`, `private` + +If successful, returns 201, a link to the created resource as a `Location` header, and the following response: + +```javascript +{ + "title": String, + "playlistId": String +} +``` + +##### GET `/api/v1/auth/playlists/:id` + +Returns same result as unauthenticated `/api/v1/playlists/:id`. + +Important to note is that if the requested playlist is marked as `private`, it will return an error if the request is not authenticated as the playlist's author. + +##### PATCH `/api/v1/auth/playlists/:id` + +`Content-Type: application/json` + +Modify a playlist's `description`, `title`, `description`, or `privacy`. + +Example request body: + +```javascript +{ + "title": String, + "description": String, + "privacy": "private" +} +``` + +`privacy` can be any of: `public`, `unlisted`, `private` + +Will return 204 on success. + +##### DELETE `/api/v1/auth/playlists/:id` + +Delete a given playlist `:id`. + +Will return 204 on success. + +##### POST `/api/v1/auth/playlists/:id/videos` + +`Content-Type: application/json` + +Add a video to the given playlist `:id`. + +Example request body: + +```javascript +{ + "videoId": String +} +``` + +Returns a 201 on success with the following schema: + +```javascript +{ + "title": String, + "videoId": String, + "author": String, + "authorId": String, + "authorUrl": String, + "videoThumbnails": [ + { + "quality": String, + "url": String, + "width": Int32, + "height": Int32 + } + ] +} +``` + +##### DELETE `/api/v1/auth/playlists/:id/videos/:index` + +Delete a video from the given playlist `:id` with `indexId` `:index`. + +Will return 204 on success. + +##### GET `/api/v1/auth/preferences` + +Get preferences for authenticated user. + +> Schema: + +```javascript +{ + "annotations": false, + "annotations_subscribed": false, + "autoplay": false, + "captions": [ + "", + "", + "" + ], + "comments": [ + "youtube", + "" + ], + "continue": false, + "continue_autoplay": true, + "dark_mode": "light", + "latest_only": false, + "listen": false, + "local": false, + "locale": "en-US", + "max_results": 40, + "notifications_only": false, + "player_style": "invidious", + "quality": "hd720", + "default_home": "Popular", + "feed_menu": [ + "Trending", + "Playlists" + ], + "related_videos": true, + "sort": "published", + "speed": 1.0, + "thin_mode": false, + "unseen_only": false, + "video_loop": false, + "volume": 100 +} +``` + +##### POST `/api/v1/auth/preferences` + +`Content-Type: application/json` + +Patch user preferences. + +Example body: + +```javascript +{ + "speed": 2.0, + "volume": 10 +} +``` + +##### GET `/api/v1/auth/subscriptions` + +Get user's subscriptions. + +> Schema: + +```javascript +[ + { + "author": String, + "authorId": String + } +] +``` + +##### POST `/api/v1/auth/subscriptions/:ucid` + +`Content-Type: application/json` + +Add a given `ucid` to a user's subscriptions. + +Will return 204 on success. + +##### DELETE `/api/v1/auth/subscriptions/:ucid` + +Removes a given `ucid` from a user's subscriptions. + +Will return 204 on success. + +##### GET `/api/v1/auth/tokens` + +Get a list of tokens for the authenticated user. + +> Schema: + +```javascript +[ + { + "session": String, + "issued": Int64 + } +] +``` + +##### POST `/api/v1/auth/tokens/register` + +`Content-Type: application/json` + +Create a new token for the authenticated user. + +Example request body: + +```javascript +{ + "scopes": Array(String), // Each scope has same format as each scope in `/authorize_token` + "callbackUrl": String?, + "expire": Int64 +} +``` + +Returns a 200 on success with the newly created token as the response body. + +Example response: + +```javascript +{ + "session":"v1:YUwKEL1XwHQzp7-AAAAAAAAAAAAAAAAAA=", + "scopes":["GET:notifications"], + "signature":"jNYdAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAXGb__2Gv-w=" +} +``` + +##### POST `/api/v1/auth/tokens/unregister` + +`Content-Type: application/json` + +Revoke a token for the authenticated user. + +Example request: + +```javascript +{ + "session": "v1:YUwKEL1XwHQzp7-AAAAAAAAAAAAAAAAAA=" +} +``` + +Returns 204 on success.