Skip to content

Commit

Permalink
Support API key authentication
Browse files Browse the repository at this point in the history
Support also authenticating with an API key -- since this is seperate
from device tokens, choose to authenticate with one if a device name is
not set.

Fixes #19
  • Loading branch information
s-t-e-v-e-n-k committed Sep 11, 2023
1 parent 8d137f4 commit ecccf0c
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 9 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ json.loads(credentials)
client.authenticate({"Servers": [credentials]}, discover=False)
```

You can also authenticate using an API key, which is generated on the server.
This is different to a device AccessToken, and is set by not configuring a
device name, or a device id:

```
client.config.data["app.name"] = 'your_brilliant_app'
client.config.data["app.version"] = '0.0.1'
client.authenticate({"Servers": [{"AccessToken: <API key here>, "address": <Server Address>}]}, discover=False)
```

### API

The API is accessed via the `jellyfin` attribute of the client. Return values
Expand Down Expand Up @@ -74,6 +84,7 @@ For details on what the individual API calls do or how to do a certain task, you
- Add timesync manager and SyncPlay API methods.
- Remove usage of `six` module.
- Add group of `remote_` API calls to remote control another session
- Add support for authenticating via an API key

## Contributing

Expand Down
3 changes: 2 additions & 1 deletion jellyfin_apiclient_python/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,8 @@ def login(self, server_url, username, password=""):

def validate_authentication_token(self, server):
headers = self.get_default_headers()
headers["Authorization"] += f", Token=\"{server['AccessToken']}\""
comma = "," if "app.device_name" in self.config.data else ""
headers["Authorization"] += f"{comma} Token=\"{server['AccessToken']}\""

response = self.send_request(server['address'], "system/info", headers=headers)
return response.json() if response.status_code == 200 else {}
Expand Down
6 changes: 4 additions & 2 deletions jellyfin_apiclient_python/connection_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ def get_available_servers(self, discover=True):
except KeyError:
continue

servers.sort(key=itemgetter('DateLastAccessed'), reverse=True)
if len(servers) > 1:
servers.sort(key=itemgetter('DateLastAccessed'), reverse=True)
credentials['Servers'] = servers
self.credentials.set(credentials)

Expand Down Expand Up @@ -336,7 +337,8 @@ def _after_connect_validated(self, server, credentials, system_info, verify_auth
if system_info:

self._update_server_info(server, system_info)
self.config.data['auth.user_id'] = server['UserId']
if "UserId" in server:
self.config.data['auth.user_id'] = server['UserId']
self.config.data['auth.token'] = server['AccessToken']

return self._after_connect_validated(server, credentials, system_info, False, options)
Expand Down
2 changes: 2 additions & 0 deletions jellyfin_apiclient_python/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ def add_update_server(self, servers, server):

if server.get('AccessToken'):
existing['AccessToken'] = server['AccessToken']

if server.get('UserId'):
existing['UserId'] = server['UserId']

if server.get('ExchangeToken'):
Expand Down
14 changes: 8 additions & 6 deletions jellyfin_apiclient_python/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,14 @@ def _process_params(self, params):
params[key] = self._replace_user_info(value)

def _get_authenication_header(self):
params = {
"Client": self.config.data['app.name'],
"Device": self.config.data['app.device_name'],
"DeviceId": self.config.data['app.device_id'],
"Version": self.config.data['app.version']
}
params = {}
if "app.device_name" in self.config.data:
params.update({
"Client": self.config.data['app.name'],
"Device": self.config.data['app.device_name'],
"DeviceId": self.config.data['app.device_id'],
"Version": self.config.data['app.version']
})
if "auth.token" in self.config.data:
params["Token"] = self.config.data['auth.token']
param_line = ", ".join(f'{k}="{v}"' for k, v in params.items())
Expand Down

0 comments on commit ecccf0c

Please sign in to comment.