Send Piped auth token via query parameter instead of header

Piped accepts the session token via either an Authorization header or an
authToken query parameter (the /feed endpoint already uses the latter form).
Switch all token-bearing Piped endpoints to the query-parameter form so the
Authorization header is free for HTTP Basic Auth from a fronting reverse
proxy. Affects subscriptions, subscribe, unsubscribe, userPlaylists, and
userPlaylist (including its nextpage pagination loop).
This commit is contained in:
Arkadiusz Fal
2026-04-06 19:48:16 +02:00
parent 8cd3aca96c
commit aed78c13fb

View File

@@ -297,11 +297,12 @@ actor PipedAPI: InstanceAPI {
/// - authToken: The auth token from login /// - authToken: The auth token from login
/// - Returns: Array of subscribed channels /// - Returns: Array of subscribed channels
func subscriptions(instance: Instance, authToken: String) async throws -> [PipedSubscription] { func subscriptions(instance: Instance, authToken: String) async throws -> [PipedSubscription] {
// Subscriptions endpoint uses Authorization header // Piped accepts the auth token via the `authToken` query parameter, which keeps the
// `Authorization` header free for HTTP Basic Auth from a fronting reverse proxy.
let endpoint = GenericEndpoint( let endpoint = GenericEndpoint(
path: "/subscriptions", path: "/subscriptions",
method: .get, method: .get,
headers: ["Authorization": authToken] queryItems: [URLQueryItem(name: "authToken", value: authToken)]
) )
let response: [PipedSubscription] = try await httpClient.fetch(endpoint, baseURL: instance.url) let response: [PipedSubscription] = try await httpClient.fetch(endpoint, baseURL: instance.url)
return response return response
@@ -321,7 +322,8 @@ actor PipedAPI: InstanceAPI {
let endpoint = GenericEndpoint( let endpoint = GenericEndpoint(
path: "/subscribe", path: "/subscribe",
method: .post, method: .post,
headers: ["Authorization": authToken, "Content-Type": "application/json"], queryItems: [URLQueryItem(name: "authToken", value: authToken)],
headers: ["Content-Type": "application/json"],
body: bodyData body: bodyData
) )
@@ -343,7 +345,8 @@ actor PipedAPI: InstanceAPI {
let endpoint = GenericEndpoint( let endpoint = GenericEndpoint(
path: "/unsubscribe", path: "/unsubscribe",
method: .post, method: .post,
headers: ["Authorization": authToken, "Content-Type": "application/json"], queryItems: [URLQueryItem(name: "authToken", value: authToken)],
headers: ["Content-Type": "application/json"],
body: bodyData body: bodyData
) )
@@ -359,7 +362,7 @@ actor PipedAPI: InstanceAPI {
let endpoint = GenericEndpoint( let endpoint = GenericEndpoint(
path: "/user/playlists", path: "/user/playlists",
method: .get, method: .get,
headers: ["Authorization": authToken] queryItems: [URLQueryItem(name: "authToken", value: authToken)]
) )
let response: [PipedUserPlaylist] = try await httpClient.fetch(endpoint, baseURL: instance.url) let response: [PipedUserPlaylist] = try await httpClient.fetch(endpoint, baseURL: instance.url)
return response.map { $0.toPlaylist() } return response.map { $0.toPlaylist() }
@@ -372,11 +375,11 @@ actor PipedAPI: InstanceAPI {
/// - authToken: The auth token from login /// - authToken: The auth token from login
/// - Returns: Playlist with videos /// - Returns: Playlist with videos
func userPlaylist(id: String, instance: Instance, authToken: String) async throws -> Playlist { func userPlaylist(id: String, instance: Instance, authToken: String) async throws -> Playlist {
let headers = ["Authorization": authToken] let authQueryItem = URLQueryItem(name: "authToken", value: authToken)
let firstEndpoint = GenericEndpoint( let firstEndpoint = GenericEndpoint(
path: "/playlists/\(id)", path: "/playlists/\(id)",
method: .get, method: .get,
headers: headers queryItems: [authQueryItem]
) )
let firstResponse: PipedPlaylistResponse = try await httpClient.fetch(firstEndpoint, baseURL: instance.url) let firstResponse: PipedPlaylistResponse = try await httpClient.fetch(firstEndpoint, baseURL: instance.url)
var allStreams = firstResponse.relatedStreams ?? [] var allStreams = firstResponse.relatedStreams ?? []
@@ -387,8 +390,7 @@ actor PipedAPI: InstanceAPI {
while let token = nextpage, page < maxPages { while let token = nextpage, page < maxPages {
let nextEndpoint = GenericEndpoint( let nextEndpoint = GenericEndpoint(
path: "/nextpage/playlists/\(id)", path: "/nextpage/playlists/\(id)",
queryItems: [URLQueryItem(name: "nextpage", value: token)], queryItems: [URLQueryItem(name: "nextpage", value: token), authQueryItem]
headers: headers
) )
let nextResponse: PipedPlaylistNextPageResponse = try await httpClient.fetch(nextEndpoint, baseURL: instance.url) let nextResponse: PipedPlaylistNextPageResponse = try await httpClient.fetch(nextEndpoint, baseURL: instance.url)
let pageStreams = nextResponse.relatedStreams ?? [] let pageStreams = nextResponse.relatedStreams ?? []