Drop the redundant force-ssl scope, and reject the playlistItems "fix"
force-ssl is gone from the requested scope. Its grant ("see, edit, and
permanently delete your videos, ratings, comments and captions") is a strict
subset of auth/youtube's ("Manage your YouTube account"), and Google's own
liveBroadcasts.insert reference lists auth/youtube as an accepted ALTERNATIVE
to force-ssl, so every endpoint this app calls — channels, liveBroadcasts,
liveStreams, liveChat, playlistItems — is covered by the one we keep. Two
consent lines became one, and one fewer scope to justify. Removing a scope
cannot narrow capability when the scope being kept is the broader of the two,
and there is no forced re-consent: a refresh token keeps the scopes it was
originally granted, so existing sessions are untouched.
The playlistItems change is NOT being made, and the map entry recommending it
was wrong. It came out of the verification hunt on the theory that public data
should not ride on user credentials. Walking the code kills it: ChannelStats-
Service is built with one HttpClient, and channels?mine=true on the same
service genuinely needs the session. Splitting it means a second unauthenticated
client PLUS a Google API key, since every YouTube Data API request needs a
credential and the call 403s without one. So the fix would ship a new
extractable, quota-abusable credential inside the binary to replace a token the
app already holds, buying zero verification-surface reduction (the data is
public, no scope involved) and zero correctness. Strictly worse. Recorded as a
do-not-do so it is not "helpfully" reintroduced later.
Test: ExactlyOneScopeIsRequested_AndItIsTheBroadOne asserts on the const's
parsed VALUE rather than scanning the file — a file-wide DoesNotContain
fails on the doc comment that names force-ssl to explain its removal, which is
the same trap I hit and documented earlier today in the locator test. Suite
380/380, 0 warnings.
This commit is contained in:
@@ -15,7 +15,25 @@ public class YouTubeAuthService
|
||||
{
|
||||
private const string AuthorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
|
||||
private const string TokenEndpoint = "https://oauth2.googleapis.com/token";
|
||||
private const string Scope = "https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl";
|
||||
/// <summary>
|
||||
/// The single scope the app requests: <c>auth/youtube</c> ("Manage your YouTube
|
||||
/// account"). It is the **broadest** YouTube scope and is unavoidable — no narrower one
|
||||
/// covers live broadcast create/transition, and Google's own <c>liveBroadcasts.insert</c>
|
||||
/// reference lists it as an accepted alternative to <c>youtube.force-ssl</c>, so every
|
||||
/// endpoint this app touches (<c>channels</c>, <c>liveBroadcasts</c>, <c>liveStreams</c>,
|
||||
/// <c>liveChat</c>, <c>playlistItems</c>) is covered by it.
|
||||
///
|
||||
/// <para><c>auth/youtube.force-ssl</c> used to be requested alongside it and was
|
||||
/// <b>dropped 2026-09-28 as redundant</b>: its grant is "see, edit, and permanently delete
|
||||
/// your YouTube videos, ratings, comments and captions", a strict subset of what
|
||||
/// <c>auth/youtube</c> already grants. Requesting both meant two consent lines and two
|
||||
/// scopes to justify for one capability. Removing a scope can never narrow capability,
|
||||
/// because the scope being kept is the broader of the two.
|
||||
///
|
||||
/// No forced re-consent: a refresh token keeps the scopes it was originally granted, so an
|
||||
/// existing session is unaffected; the reduced set applies from the next fresh sign-in.</para>
|
||||
/// </summary>
|
||||
private const string Scope = "https://www.googleapis.com/auth/youtube";
|
||||
|
||||
private readonly string _clientId;
|
||||
private readonly string _clientSecret;
|
||||
|
||||
Reference in New Issue
Block a user