GeoffreyCoulaud / jellyfin-api-client

A client library for accessing Jellyfin API
MIT License
4 stars 1 forks source link

HTTPStatus.UNAUTHORIZED #1

Closed PhantomPhoton closed 6 months ago

PhantomPhoton commented 6 months ago

So I'm trying to use this library on JellyFin 10.8.13. I went to Administration -> API Keys and created a new key.

I'm attempting to get a list of items and so here's my code, obviously with BASE_URL and TOKEN being set to valid values.

from jellyfin_api_client import AuthenticatedClient
from jellyfin_api_client.api.items import get_items
import pprint

BASE_URL="BASE_URL"
TOKEN="TOKEN"

with AuthenticatedClient(base_url=BASE_URL, token=TOKEN) as client:
        pprint.pp(client)
        data = get_items.sync_detailed(client=client)
        pprint.pp(data)

I'm receiving this result

AuthenticatedClient(raise_on_unexpected_status=False, _base_url='BASE_URL', _cookies={}, _headers={'Authorization': 'Bearer TOKEN'}, _timeout=None, _verify_ssl=True, _follow_redirects=False, _httpx_args={}, _client=<httpx.Client object at 0x1058e6cf0>, _async_client=None, token='TOKEN', prefix='Bearer', auth_header_name='Authorization')
Response(status_code=<HTTPStatus.UNAUTHORIZED: 401>, content=b'', headers=Headers({'alt-svc': 'h3=":443"; ma=2592000', 'content-length': '0', 'date': 'Sun, 07 Apr 2024 18:02:56 GMT', 'referrer-policy': 'no-referrer', 'server': 'Kestrel', 'strict-transport-security': 'max-age=315360000; includeSubDomains; preload', 'x-content-type-options': 'nosniff', 'x-frame-options': 'allow-from BASE_URL', 'x-response-time-ms': '1', 'x-robots-tag': 'none', 'x-xss-protection': '1; mode=block'}), parsed=None)

When looking at the jellyfin logs

[11:09:12] [DBG] [67] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: CustomAuthentication was not authenticated.
[11:09:12] [DBG] [67] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: CustomAuthentication was not authenticated.
[11:09:12] [INF] [67] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: CustomAuthentication was challenged

Is there a different api key location I need to generate? or am I using the AuthenticatedClient incorrectly?

Thank you very much!

GeoffreyCoulaud commented 6 months ago

Hello,

This is expected behaviour, but it's also my fault for not documenting the project so much. The expected token is not an API key, but an access token handed by the server.

Here is a snippet extracted from Marmalade's code showing how that token is obtained :

from http import HTTPStatus

from jellyfin_api_client.api.user import authenticate_user_by_name
from jellyfin_api_client.errors import UnexpectedStatus
from jellyfin_api_client.models.authenticate_user_by_name import AuthenticateUserByName
from jellyfin_api_client.models.authentication_result import AuthenticationResult
from src.jellyfin import JellyfinClient, make_device_id

def main(username: str, password: str, base_url: str) -> AuthenticationResult:
    device_id = make_device_id()
    client = JellyfinClient(base_url=base_url, device_id=device_id)
    response = authenticate_user_by_name.sync_detailed(
        client=client,
        json_body=AuthenticateUserByName(username=username, pw=password),
    )
    if response.status_code == HTTPStatus.OK:
        return response.parsed
    if response.status_code == HTTPStatus.UNAUTHORIZED:
        raise ValueError("Invalid username or password")
    raise UnexpectedStatus(response.status_code, response.content)

def on_success(result: AuthenticationResult) -> None:
    print(f"Authenticated {result.user.name}")
    print(f"Access token: {result.access_token}")

Don't hesitate to ask me if you have any more questions. I suggest poking around Marmalade's codebase to get more examples of how to use that library, but beware, it's experimental and I've not touched it in a while.