fix(sync): 403 insufficientPermissions -> scope youtube complet + invite reconnect
This commit is contained in:
@@ -681,6 +681,10 @@ r.get('/oauth/google/watchlater', authMiddlewareCookieAware, oauthLimiter, async
|
||||
} catch (error) {
|
||||
const out = { error: error?.message || 'watchlater_fetch_failed' };
|
||||
if (error?.hint) out.hint = error.hint;
|
||||
if (error?.ytReason) out.ytReason = error.ytReason;
|
||||
if (!out.hint && String(error?.ytReason || '').toLowerCase().includes('insufficientpermissions')) {
|
||||
out.hint = 'Scope manquant : déconnectez puis reconnectez Google pour autoriser l’accès complet YouTube.';
|
||||
}
|
||||
return res.status(error?.status || 502).json(out);
|
||||
}
|
||||
});
|
||||
@@ -719,6 +723,8 @@ r.get('/oauth/google/yt-history', authMiddlewareCookieAware, oauthLimiter, async
|
||||
if (error?.ytReason) out.ytReason = error.ytReason;
|
||||
if (error?.status === 401) {
|
||||
out.hint = 'Session Google expirée : déconnectez puis reconnectez Google.';
|
||||
} else if (String(error?.ytReason || '').toLowerCase().includes('insufficientpermissions')) {
|
||||
out.hint = 'Scope manquant : déconnectez puis reconnectez Google pour autoriser l’accès complet YouTube.';
|
||||
}
|
||||
return res.status(error?.status || 502).json(out);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ const GOOGLE_SCOPES = [
|
||||
// Écriture Watch Later (playlistItems.insert/delete). Lecture seule
|
||||
// (abos, likes, WL) fonctionne sans lui ; le push exige un re-consentement.
|
||||
'https://www.googleapis.com/auth/youtube.force-ssl',
|
||||
// InnerTube authentifié (historique FEhistory, playlist WL) exige le scope
|
||||
// complet : avec readonly seul, YouTube répond 403 insufficientPermissions.
|
||||
// Les connexions existantes doivent se reconnecter pour l'obtenir.
|
||||
'https://www.googleapis.com/auth/youtube',
|
||||
].join(' ');
|
||||
|
||||
/** Le jeton stocké permet-il l'écriture (push Watch Later) ? */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<details class="mb-4 rounded-xl border border-slate-800 bg-slate-900/60 p-4 text-sm text-slate-300">
|
||||
<summary class="cursor-pointer font-semibold text-slate-100">Comment ça marche ? (scopes, URLs, ré-import)</summary>
|
||||
<ul class="mt-2 list-disc space-y-1 pl-5 text-slate-400">
|
||||
<li><strong class="text-slate-200">Google</strong> : abonnements + favoris YouTube, scopes <code>openid userinfo.profile youtube.readonly</code> (+ <code>youtube.force-ssl</code> pour pousser vers Regarder plus tard). Redirect URI à enregistrer dans Google Cloud : <code>/api/oauth/google/callback</code>.</li>
|
||||
<li><strong class="text-slate-200">Google</strong> : abonnements + favoris YouTube, scopes <code>openid userinfo.profile youtube.readonly youtube.force-ssl youtube</code> (le scope complet est requis pour la sync auto et Regarder plus tard via InnerTube — reconnectez-vous après chaque élargissement). Redirect URI à enregistrer dans Google Cloud : <code>/api/oauth/google/callback</code>.</li>
|
||||
<li><strong class="text-slate-200">Twitch</strong> : chaînes suivies uniquement (<strong>pas de likes côté Twitch</strong>), scopes <code>user:read:follows user:read:subscriptions</code>. Redirect URI à enregistrer sur dev.twitch.tv : <code>/api/oauth/twitch/callback</code>.</li>
|
||||
<li><strong class="text-slate-200">Prévisualiser</strong> ne change rien ; <strong class="text-slate-200">Importer</strong> ajoute abonnements / favoris dans NewTube.</li>
|
||||
<li>Ré-importer est <strong class="text-slate-200">sans doublons</strong> : relancez sans crainte après de nouveaux abos/likes.</li>
|
||||
|
||||
@@ -252,7 +252,9 @@ export class ImportComponent implements OnInit {
|
||||
error: (e) => {
|
||||
const code = e?.error?.error || e?.message || 'watchlater_fetch_failed';
|
||||
const hint = e?.error?.hint;
|
||||
this.wlError.set(hint ? `${code} — ${hint}` : code);
|
||||
const ytReason = e?.error?.ytReason;
|
||||
const extra = [hint, ytReason ? `YouTube: ${ytReason}` : ''].filter(Boolean).join(' — ');
|
||||
this.wlError.set(extra ? `${code} — ${extra}` : code);
|
||||
this.wlLoading.set(false);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user