Netflix MSL Universal Handshake
A cross-platform MSL (Message Security Layer) authentication toolkit for Netflix.
Implements a unified handshake layer that works across Android, iOS, Smart TV, Web, and MGK — all driven from a single entry point with shared credential management.
Table of Contents
Install all dependencies:
pip install -r requirements.txt
Configuration
Edit config.ini before running anything:
[NETFLIX]
EMAIL = your@email.com
PASSWORD = yourpassword
Credentials are read once at startup and passed internally to every platform function. They are never accepted as command-line arguments.
Devices (WVD Files)
Two Widevine Device (.wvd) files are included in the devices/ folder:
| File | Security Level | Used by |
|---|---|---|
l3.wvd |
L3 | Android, iOS |
l1.wvd |
L1 | TV, TV OTP |
The correct WVD is selected automatically for each platform. The --wvd flag lets you override with a custom device file if needed.
Platforms
Android
Emulates a Samsung Galaxy Z Flip3 (SM-F711N) running Android 15.
MSL flow:
- Bootstrap HTTP session → obtain
nfvdidcookie viaappboot - Widevine key exchange (MSL handshake) using L3 WVD
VerifyLoginMslRequest— submits email + password via MSL- Decrypts the response header to extract
useridtoken
Output: netflix_auth_tokens.json, netflix_auth_useridtoken.json, netflix_auth_cookies.json
iOS
Emulates an iPhone 15 Pro Max running iOS 18.
MSL flow:
- Bootstrap HTTP session → obtain
nfvdidviaappboot - Widevine key exchange using L3 WVD
MembershipStatusGraphQL probe (anonymous)CLCSScreenUpdate— submits email + password via MSL toios.prod.cloud.netflix.com/graphql- Decrypts the response header to extract
useridtoken
Output: netflix_auth_cookies.json
TV (email/password)
Emulates an NVIDIA SHIELD Android TV (2019).
MSL flow:
- Obtain
nfvdidfrom the Android TV config endpoint - Bootstrap AUI + pre-login
pathEvaluator - Widevine key exchange using L1 WVD →
mintCookies - CLCS session initiation (
clcsLegacyMoneyballInitiateSession) - Multi-step sign-in flow:
- Navigate welcome landing → web sign-in → email → password path
- Submit credentials via
clcsScreenUpdate
- Post-login PBO config + token refresh (
getPartnerToken,ping) - Save cookies including
NetflixId,SecureNetflixId,gsid
Output: netflix_cookies.json, useridtoken.json, msl_debug_trace.json, password_login_response.json
TV OTP (pairing code)
Same device profile as TV, but authenticates via a one-time pairing code instead of email/password.
MSL flow:
1–3. Same as TV up through mintCookies
4. CLCS session initiation
5. Navigate to webSignIn mode → extract an 8-digit TV code
6. Display the code and poll https://www.netflix.com/tv2 until the user activates it from a browser
7. Send continueAction to complete sign-in
Interactive: you must visit
https://www.netflix.com/tv2in a browser and enter the displayed code to proceed.
Output: netflix_cookies.json, useridtoken.json
Web
Emulates Chrome 146 on Windows 10.
MSL flow:
- Bootstrap anonymous browser session (
netflix.com→netflix.com/login) MembershipStatusGraphQL probe- Extract
clcsSessionIdandrenditionIdfrom the login page HTML CLCSScreenUpdate— submit email + password directly toPASSWORD_LOGINscreen- Optional
CLCSSendFeedbackif the response contains a feedback payload - Open
/browseto finalize the authenticated session CLCSInterstitialProfileGateprobe- ALE provision via MSL (
aleProvisionhandshake)
Output: netflix_auth_cookies.json
MGK (Model Group Key)
Uses the MGK / AUTHENTICATED_DH MSL key-exchange scheme, authenticating with a pre-provisioned KpeKph key pair rather than a Widevine device.
Requires two sidecar files:
| File | Content |
|---|---|
KpeKph |
Base64 AES-128 encryption key + Base64 HMAC-SHA256 key, comma-separated |
ESNID |
Model-group identity string (the MGK sender ESN) |
These files are discovered automatically in the working directory, any subdirectory, or via environment variables:
export MSL_KPEKPH_PATH=/path/to/KpeKph
export MSL_ESNID_PATH=/path/to/ESNID
Or pass --kpekph on the command line.
MSL flow:
- Load
KpeKph→ derive wrapping key - Generate a DH keypair; build
AUTHENTICATED_DHkey-request withmechanism=MGK - Perform handshake → derive session encryption + HMAC keys from shared secret
- Send
EMAIL_PASSWORDuser-auth message → receiveuseridtoken
Output: useridtoken_mgk.json, netflix_auth_cookies_mgk.json
Usage
# Android
python main.py --platform android
# iOS
python main.py --platform ios
# TV (email/password)
python main.py --platform tv
# TV OTP (pairing code — interactive)
python main.py --platform tv_otp
# Web (Chrome emulation)
python main.py --platform web
# MGK (Model Group Key)
python main.py --platform mgk
# MGK with explicit KpeKph path
python main.py --platform mgk --kpekph /path/to/KpeKph
# Override WVD device for Android/iOS/TV/TV-OTP
python main.py --platform android --wvd /path/to/device.wvd
# Force a fresh MSL key exchange (ignore cached keys)
python main.py --platform tv --new-msl
# Disable TLS verification (not recommended)
python main.py --platform web --no-verify
# Pass a reCAPTCHA token for web login
python main.py --platform web --recaptcha-token <token>
All flags
| Flag | Applies to | Description |
|---|---|---|
--platform / -p |
all | Required. android, ios, tv, tv_otp, web, mgk |
--wvd |
android, ios, tv, tv_otp | Path to .wvd Widevine device file (optional override) |
--kpekph |
mgk | Path to KpeKph key file |
--new-msl |
all | Force a fresh MSL handshake, ignoring any cached keys |
--no-verify |
all | Disable TLS certificate verification |
--recaptcha-token |
web | reCAPTCHA v2 response token |
MSL key caches are reused across runs to avoid a full handshake every time. They expire automatically when the master token has fewer than 10 hours remaining.
Big thanks to Hugoved
- for the foundational work on MSL (Message Security Layer) reverse engineering, and the original pywidevine implementation that made this unified handshake toolkit possible.