Use VIAPLAY-AT auth scheme for account overview.

Bearer was rejected with Forbidden; manage-account HAR uses VIAPLAY-AT.
This commit is contained in:
Jos Vooges | STH 2026-09-22 23:14:40 +02:00
parent 1c939acd59
commit 0424ec4a10
4 changed files with 18 additions and 10 deletions

View file

@ -536,7 +536,7 @@ export function ViaplayPanel({ onChanged }: { onChanged?: (o: ViaplayOverview) =
onChange={(e) => setEditAccessToken(e.target.value)} onChange={(e) => setEditAccessToken(e.target.value)}
rows={2} rows={2}
disabled={busy} disabled={busy}
placeholder="nieuw accessToken (voor pakketinfo vereist)" placeholder="JWT of VIAPLAY-AT … (cookie accessToken)"
style={{ fontFamily: "monospace", fontSize: "0.8rem" }} style={{ fontFamily: "monospace", fontSize: "0.8rem" }}
/> />
</label> </label>

View file

@ -130,7 +130,10 @@ export function createAccountStored(
const email = input.email.trim().toLowerCase(); const email = input.email.trim().toLowerCase();
if (!email) throw new Error("E-mail verplicht"); if (!email) throw new Error("E-mail verplicht");
const session = input.session?.trim(); const session = input.session?.trim();
const accessToken = input.accessToken?.trim().replace(/^Bearer\s+/i, "").trim(); const accessToken = input.accessToken
?.trim()
.replace(/^(VIAPLAY-AT|MTG-AT|Bearer)\s+/i, "")
.trim();
if (!session || !accessToken) { if (!session || !accessToken) {
throw new Error("session + accessToken verplicht"); throw new Error("session + accessToken verplicht");
} }

View file

@ -77,7 +77,10 @@ function normalizeAccessToken(raw: string | null | undefined): string | null {
if (!raw) return null; if (!raw) return null;
const trimmed = raw.trim(); const trimmed = raw.trim();
if (!trimmed) return null; if (!trimmed) return null;
return trimmed.replace(/^Bearer\s+/i, "").trim() || null; // Browser/HAR kan "VIAPLAY-AT …", "MTG-AT …" of "Bearer …" plakken
return (
trimmed.replace(/^(VIAPLAY-AT|MTG-AT|Bearer)\s+/i, "").trim() || null
);
} }
function accessTokenExpiryInfo(token: string): { function accessTokenExpiryInfo(token: string): {
@ -98,7 +101,7 @@ function accessTokenExpiryInfo(token: string): {
/** /**
* Pakketinfo komt van account.mtg-api.com/overview. * Pakketinfo komt van account.mtg-api.com/overview.
* Browser stuurt alleen Authorization: Bearer (geen cookies) — cookies geven Forbidden. * Browser (HAR): Authorization: VIAPLAY-AT <jwt> — geen cookies, geen Bearer.
*/ */
export async function fetchAccountOverview( export async function fetchAccountOverview(
creds: ViaplayAccountCreds, creds: ViaplayAccountCreds,
@ -118,15 +121,14 @@ export async function fetchAccountOverview(
} }
const tokenInfo = accessTokenExpiryInfo(token); const tokenInfo = accessTokenExpiryInfo(token);
// Exact zoals manage-account in de browser (HAR): Bearer-only + Content-Type
const headers: Record<string, string> = { const headers: Record<string, string> = {
Accept: "*/*", Accept: "*/*",
"Content-Type": "application/json", "Content-Type": "application/json",
"Accept-Language": "nl,en-US;q=0.7,en;q=0.3", "Accept-Language": "nl,en-US;q=0.9,en;q=0.8",
Origin: "https://viaplay.com", Origin: "https://viaplay.com",
Referer: "https://viaplay.com/", Referer: "https://viaplay.com/",
"User-Agent": VIAPLAY_USER_AGENT, "User-Agent": VIAPLAY_USER_AGENT,
Authorization: `Bearer ${token}`, Authorization: `VIAPLAY-AT ${token}`,
}; };
let lastStatus = 0; let lastStatus = 0;
@ -177,8 +179,8 @@ export async function fetchAccountOverview(
(lastStatus === 401 || lastStatus === 403 || /forbidden|unauthorized/i.test(lastError)) (lastStatus === 401 || lastStatus === 403 || /forbidden|unauthorized/i.test(lastError))
) { ) {
lastError = tokenInfo.expired lastError = tokenInfo.expired
? "accessToken verlopen — plak een verse accessToken uit de browser en Check opnieuw" ? "accessToken verlopen — vernieuw tokens en Check opnieuw"
: "overview Forbidden — plak een verse accessToken (Bearer) uit de browser; sessiecookie is niet genoeg"; : `overview ${lastError} (Authorization moet VIAPLAY-AT zijn)`;
} }
return { return {

View file

@ -261,7 +261,10 @@ export async function updateViaplayAccount(
sessionEnc = encryptSecret(input.session.trim(), sessionSecret); sessionEnc = encryptSecret(input.session.trim(), sessionSecret);
} }
if (input.accessToken?.trim()) { if (input.accessToken?.trim()) {
const token = input.accessToken.trim().replace(/^Bearer\s+/i, "").trim(); const token = input.accessToken
.trim()
.replace(/^(VIAPLAY-AT|MTG-AT|Bearer)\s+/i, "")
.trim();
accessTokenEnc = encryptSecret(token, sessionSecret); accessTokenEnc = encryptSecret(token, sessionSecret);
} }
if (input.profileId !== undefined) { if (input.profileId !== undefined) {