[GH-ISSUE #781] Missing Authorization header in browser.json causes wrong AuthType detection (OAUTH_CUSTOM_CLIENT instead of BROWSER) #497

Closed
opened 2026-02-27 23:01:07 +03:00 by kerem · 12 comments
Owner

Originally created by @Serelue on GitHub (Jun 29, 2025).
Original GitHub issue: https://github.com/sigma67/ytmusicapi/issues/781

  • I confirm that I have read the FAQ

Describe the bug

Hello, I manually created browser.json following the guide (https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html#manual-file-creation)

However, ytmusicapi recognizes this file as AuthType.OAUTH_CUSTOM_CLIENT instead of AuthType.BROWSER, which causes an error.

Traceback (most recent call last):
  File "D:\dev\dev6.py", line 4, in <module>
    ytmusic = YTMusic("./browser.json")
  File "D:\dev\.venv\lib\site-packages\ytmusicapi\ytmusic.py", line 105, in __init__
    raise YTMusicUserError(
ytmusicapi.exceptions.YTMusicUserError: oauth JSON provided via auth argument, but oauth_credentials not provided.Please provide oauth_credentials as specified in the OAuth setup documentation.

I've written the solution below, but I'm not sure if this is a documentation issue or a code issue, so I'm posting this as a bug.

ytmusicapi version

1.10.3

To Reproduce

from ytmusicapi import YTMusic

ytmusic = YTMusic("./browser.json")
print(ytmusic.search("Never Gonna Give You Up"))

Additional context

browser.json file I used in my first attempt was:

{
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
    "Accept": "*/*",
    "Accept-Language": "en-US,en;q=0.5",
    "Content-Type": "application/json",
    "X-Goog-AuthUser": "0",
    "x-origin": "https://music.youtube.com",
    "Cookie" : "<COOKIE>"
}

I was looking for where the error occurs and I found the determine_auth_type func.

# ytmusicapi.auth.auth_parse.py
# line 34
def determine_auth_type(auth_headers: CaseInsensitiveDict) -> AuthType:
    """
    Determine the type of auth based on auth headers.

    :param auth_headers: auth headers dict
    :return: AuthType enum
    """
    auth_type = AuthType.OAUTH_CUSTOM_CLIENT
    if OAuthToken.is_oauth(auth_headers):
        auth_type = AuthType.OAUTH_CUSTOM_CLIENT

    if authorization := auth_headers.get("authorization"):
        if "SAPISIDHASH" in authorization:
            auth_type = AuthType.BROWSER
        elif authorization.startswith("Bearer"):
            auth_type = AuthType.OAUTH_CUSTOM_FULL

    return auth_type

I suspected that the issue was caused by browser.json(self._auth_headers, auth_headers) failing to find the Authorization header

because this header was displayed in the browser request.

Authorization header (on browser)
SAPISIDHASH asdfasdfasdfasdf SAPISID1PHASH asdfasdfasdfasdf SAPISID3PHASH asdfasdfasdfasdf

I changed browser.json like this, and it works,

{
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
    "Accept": "*/*",
    "Authorization": "SAPISIDHASH asdfasdfasdfasdf SAPISID1PHASH asdfasdfasdfasdf SAPISID3PHASH asdfasdfasdfasdf",
    "Accept-Language": "en-US,en;q=0.5",
    "Content-Type": "application/json",
    "X-Goog-AuthUser": "0",
    "x-origin": "https://music.youtube.com",
    "Cookie" : "<COOKIE>"
}

https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html#manual-file-creation

There was nothing about Authorization header in the documentation. (or maybe it's my mistake)

Originally created by @Serelue on GitHub (Jun 29, 2025). Original GitHub issue: https://github.com/sigma67/ytmusicapi/issues/781 - [x] I confirm that I have read the [FAQ](https://ytmusicapi.readthedocs.io/en/stable/faq.html#why-is-ytmusicapi-returning-more-results-than-requested-with-the-limit-parameter) **Describe the bug** Hello, I manually created browser.json following the guide (https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html#manual-file-creation) However, ytmusicapi recognizes this file as AuthType.OAUTH_CUSTOM_CLIENT instead of AuthType.BROWSER, which causes an error. ```bash Traceback (most recent call last): File "D:\dev\dev6.py", line 4, in <module> ytmusic = YTMusic("./browser.json") File "D:\dev\.venv\lib\site-packages\ytmusicapi\ytmusic.py", line 105, in __init__ raise YTMusicUserError( ytmusicapi.exceptions.YTMusicUserError: oauth JSON provided via auth argument, but oauth_credentials not provided.Please provide oauth_credentials as specified in the OAuth setup documentation. ``` I've written the solution below, but I'm not sure if this is a documentation issue or a code issue, so I'm posting this as a bug. **ytmusicapi version** 1.10.3 **To Reproduce** ```python from ytmusicapi import YTMusic ytmusic = YTMusic("./browser.json") print(ytmusic.search("Never Gonna Give You Up")) ``` **Additional context** browser.json file I used in my first attempt was: ```json { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", "Accept": "*/*", "Accept-Language": "en-US,en;q=0.5", "Content-Type": "application/json", "X-Goog-AuthUser": "0", "x-origin": "https://music.youtube.com", "Cookie" : "<COOKIE>" } ``` I was looking for where the error occurs and I found the determine_auth_type func. ```python # ytmusicapi.auth.auth_parse.py # line 34 def determine_auth_type(auth_headers: CaseInsensitiveDict) -> AuthType: """ Determine the type of auth based on auth headers. :param auth_headers: auth headers dict :return: AuthType enum """ auth_type = AuthType.OAUTH_CUSTOM_CLIENT if OAuthToken.is_oauth(auth_headers): auth_type = AuthType.OAUTH_CUSTOM_CLIENT if authorization := auth_headers.get("authorization"): if "SAPISIDHASH" in authorization: auth_type = AuthType.BROWSER elif authorization.startswith("Bearer"): auth_type = AuthType.OAUTH_CUSTOM_FULL return auth_type ``` I suspected that the issue was caused by browser.json(self._auth_headers, auth_headers) failing to find the Authorization header because this header was displayed in the browser request. ```plain Authorization header (on browser) SAPISIDHASH asdfasdfasdfasdf SAPISID1PHASH asdfasdfasdfasdf SAPISID3PHASH asdfasdfasdfasdf ``` I changed browser.json like this, and it works, ```json { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", "Accept": "*/*", "Authorization": "SAPISIDHASH asdfasdfasdfasdf SAPISID1PHASH asdfasdfasdfasdf SAPISID3PHASH asdfasdfasdfasdf", "Accept-Language": "en-US,en;q=0.5", "Content-Type": "application/json", "X-Goog-AuthUser": "0", "x-origin": "https://music.youtube.com", "Cookie" : "<COOKIE>" } ``` https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html#manual-file-creation There was nothing about Authorization header in the documentation. (or maybe it's my mistake)
kerem 2026-02-27 23:01:07 +03:00
Author
Owner

@sigma67 commented on GitHub (Aug 30, 2025):

How did you create browser.json ? I don't think the example in the docs is up to date and complete, therefore I recommend to use the CLI.

<!-- gh-comment-id:3239501612 --> @sigma67 commented on GitHub (Aug 30, 2025): How did you create browser.json ? I don't think the example in the docs is up to date and complete, therefore I recommend to use the CLI.
Author
Owner

@Serelue commented on GitHub (Aug 31, 2025):

How did you create browser.json ? I don't think the example in the docs is up to date and complete, therefore I recommend to use the CLI.

I don't remember exactly, but for some reason there was a problem with the CLI, so I created it manually.

<!-- gh-comment-id:3239639060 --> @Serelue commented on GitHub (Aug 31, 2025): > How did you create browser.json ? I don't think the example in the docs is up to date and complete, therefore I recommend to use the CLI. I don't remember exactly, but for some reason there was a problem with the CLI, so I created it manually.
Author
Owner

@CodinMoldovanu commented on GitHub (Sep 8, 2025):

I've run into this as well, even when using the ytmusicapi browser option, it doesn't ouput an Authorization field.

<!-- gh-comment-id:3268136998 --> @CodinMoldovanu commented on GitHub (Sep 8, 2025): I've run into this as well, even when using the `ytmusicapi browser` option, it doesn't ouput an Authorization field.
Author
Owner

@sigma67 commented on GitHub (Sep 9, 2025):

Having a closer look at this it seems the format has changed: https://stackoverflow.com/questions/79378674/figuring-out-google-hashing-algorithm-for-sapisidhash-used-on-youtube-subscribe

<!-- gh-comment-id:3269106047 --> @sigma67 commented on GitHub (Sep 9, 2025): Having a closer look at this it seems the format has changed: https://stackoverflow.com/questions/79378674/figuring-out-google-hashing-algorithm-for-sapisidhash-used-on-youtube-subscribe
Author
Owner

@joshhubert-dsp commented on GitHub (Sep 10, 2025):

Yeah it looks like auth/browser.py doesn't correctly handle the current format for copied headers from Chrome. To be clear, the only thing missing from the minimal manual example in the docs is the "Authorization" field, so probably worth just telling Chrome users to use that.

<!-- gh-comment-id:3273408035 --> @joshhubert-dsp commented on GitHub (Sep 10, 2025): Yeah it looks like `auth/browser.py` doesn't correctly handle the current format for copied headers from Chrome. To be clear, the only thing missing from the minimal manual example in the docs is the "Authorization" field, so probably worth just telling Chrome users to use that.
Author
Owner

@sigma67 commented on GitHub (Sep 10, 2025):

I would be in favor of fixing the issue additionally. What is going wrong for Chrome?

<!-- gh-comment-id:3273461568 --> @sigma67 commented on GitHub (Sep 10, 2025): I would be in favor of fixing the issue additionally. What is going wrong for Chrome?
Author
Owner

@joshhubert-dsp commented on GitHub (Sep 10, 2025):

When directly copying the header from dev tools starting from "accept", there are no key/value delimiters, everything's just on its own line like:

accept
*/*
accept-encoding
gzip, deflate, br, zstd
accept-language
en-US,en;q=0.9
authorization
SAPISIDHASH ... SAPISID1PHASH ... SAPISID3PHASH ...
...

and that's not being handled properly. The function does header = content.split(": ") for each line, and for me at least ": " doesn't appear in the text.

So I end up with:

  File "ytmusicapi/auth/browser.py", line 51, in setup_browser
    raise YTMusicUserError(
ytmusicapi.exceptions.YTMusicUserError: The following entries are missing in your headers: cookie, x-goog-authuser. Please try a different request (such as /browse) and make sure you are logged in.
<!-- gh-comment-id:3273505995 --> @joshhubert-dsp commented on GitHub (Sep 10, 2025): When directly copying the header from dev tools starting from "accept", there are no key/value delimiters, everything's just on its own line like: ``` accept */* accept-encoding gzip, deflate, br, zstd accept-language en-US,en;q=0.9 authorization SAPISIDHASH ... SAPISID1PHASH ... SAPISID3PHASH ... ... ``` and that's not being handled properly. The function does `header = content.split(": ")` for each line, and for me at least ": " doesn't appear in the text. So I end up with: ``` File "ytmusicapi/auth/browser.py", line 51, in setup_browser raise YTMusicUserError( ytmusicapi.exceptions.YTMusicUserError: The following entries are missing in your headers: cookie, x-goog-authuser. Please try a different request (such as /browse) and make sure you are logged in. ```
Author
Owner

@srajangarg commented on GitHub (Sep 19, 2025):

yeah, somehow chrome changed this recently. no longer has the : delimiters. for now, i just manually added them myself, but it sucks to do that

<!-- gh-comment-id:3312978642 --> @srajangarg commented on GitHub (Sep 19, 2025): yeah, somehow chrome changed this recently. no longer has the `:` delimiters. for now, i just manually added them myself, but it sucks to do that
Author
Owner

@joshhubert-dsp commented on GitHub (Sep 20, 2025):

Ohhh, I totally missed the "Raw" checkbox at the top of the headers section in Chrome dev tools. That adds back the delimiters and solves the problem.

<!-- gh-comment-id:3314624122 --> @joshhubert-dsp commented on GitHub (Sep 20, 2025): Ohhh, I totally missed the "Raw" checkbox at the top of the headers section in Chrome dev tools. That adds back the delimiters and solves the problem.
Author
Owner

@sigma67 commented on GitHub (Oct 21, 2025):

The checkbox is missing for HTTP2 requests so that's not a solution. Unfortunately there is no way around this (uncalled for) change by Chrome. So I'm tempted to just remove the Chrome part from the documentation and require to use Firefox.

<!-- gh-comment-id:3429170301 --> @sigma67 commented on GitHub (Oct 21, 2025): The checkbox is missing for HTTP2 requests so that's not a solution. Unfortunately there is no way around this (uncalled for) change by Chrome. So I'm tempted to just remove the Chrome part from the documentation and require to use Firefox.
Author
Owner

@blahster commented on GitHub (Nov 27, 2025):

Chrome instructions are now updated.
Essentially, you can use “Copy as fetch (Node.js)” instead to copy headers and clean it up a bit to include only the necessary fields.

<!-- gh-comment-id:3583955466 --> @blahster commented on GitHub (Nov 27, 2025): [Chrome instructions](https://ytmusicapi.readthedocs.io/en/stable/setup/browser.html) are now updated. Essentially, you can use “Copy as fetch (Node.js)” instead to copy headers and clean it up a bit to include only the necessary fields.
Author
Owner

@sigma67 commented on GitHub (Nov 27, 2025):

https://github.com/sigma67/ytmusicapi/pull/833

thanks @blahster

<!-- gh-comment-id:3585177815 --> @sigma67 commented on GitHub (Nov 27, 2025): https://github.com/sigma67/ytmusicapi/pull/833 thanks @blahster
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ytmusicapi#497
No description provided.