Skip to content

Instantly share code, notes, and snippets.

@sbogomolov
Last active September 21, 2025 19:05
Show Gist options
  • Select an option

  • Save sbogomolov/9616776b276bd0e9e15a740001697d06 to your computer and use it in GitHub Desktop.

Select an option

Save sbogomolov/9616776b276bd0e9e15a740001697d06 to your computer and use it in GitHub Desktop.
Property Mapping for authentik: Tautulli authentication using Plex SSO token or username and password
from authentik.sources.plex.models import UserPlexSourceConnection
base_url = "http://tautulli.apps:8181"
end_point = "/auth/signin"
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
def auth_with_plex():
connection = UserPlexSourceConnection.objects.filter(user=request.user).first()
if not connection:
ak_logger.info("Tautulli: No Plex connection found")
return {}
data = f'token={connection.plex_token}&remember_me=1'
response = requests.post(base_url + end_point, headers=headers, data=data)
if response.status_code == 200:
cookie_obj = None
for key, value in response.cookies.items():
if key.startswith("tautulli_token"):
cookie_obj = f"{key}={value}"
break
if not cookie_obj:
ak_logger.error("Tautulli: Cannot get tautulli_token")
return {}
return {
"ak_proxy": {
"user_attributes": {
"additionalHeaders": {
"Cookie": cookie_obj
}
}
}
}
else:
ak_logger.error(f"Tautulli: The request failed with: {response.text}")
return {}
def auth_with_credentials():
if "tautulli_user" not in request.user.attributes:
ak_logger.info("Tautulli: user does not have tautulli_user attribute")
return {}
if "tautulli_pass" not in request.user.attributes:
ak_logger.info("Tautulli: user does not have tautulli_pass attribute")
return {}
username = request.user.attributes["tautulli_user"]
password = request.user.attributes["tautulli_pass"]
data = f'username={username}&password={password}&remember_me=1'
response = requests.post(base_url + end_point, headers=headers, data=data)
if response.status_code == 200:
cookie_obj = None
for key, value in response.cookies.items():
if key.startswith("tautulli_token"):
cookie_obj = f"{key}={value}"
break
if not cookie_obj:
ak_logger.error("Tautulli: Cannot get tautulli_token")
return {}
return {
"ak_proxy": {
"user_attributes": {
"additionalHeaders": {
"Cookie": cookie_obj
}
}
}
}
else:
ak_logger.error(f"Tautulli: The request failed with: {response.text}")
return {}
ak_logger.info("Tautulli: Trying to authenticate with Plex token")
additionalHeaders = auth_with_plex()
if additionalHeaders:
ak_logger.info("Tautulli: Successfully authenticated with Plex token")
return additionalHeaders
ak_logger.info("Tautulli: Trying to authenticate with username and password")
additionalHeaders = auth_with_credentials()
if additionalHeaders:
ak_logger.info("Tautulli: Successfully authenticated with username and password")
return additionalHeaders
ak_logger.info("Tautulli: Authentication failed")
return {}
@sbogomolov
Copy link
Author

I’m not sure how to set it up on the nginx side, I use Traefik. Currently I do not have access to my cluster. I will be able to help with the configuration in two weeks. Ping me at the end of August if you will not figure it out by then.

@pparedes1
Copy link

similarly, thanks for sharing how to do this with authentik/traefik/tautulli. For your consideration, a slightly more resilient version below.

import requests

base_url = "http://tautulli:8181"
end_point = "/auth/signin"
headers = {
    "Content-Type": "application/x-www-form-urlencoded",
}

def authenticate_tautulli(data):
    try:
        response = requests.post(base_url + end_point, headers=headers, data=data, timeout=5)
        if response.status_code == 200:
            cookie_obj = None
            for key, value in response.cookies.items():
                if key.startswith("tautulli_token"):
                    cookie_obj = f"{key}={value}"
                    break
            if not cookie_obj:
                ak_logger.error("Tautulli: Cannot get tautulli_token")
                return {}
            return {
                "ak_proxy": {
                    "user_attributes": {
                        "additionalHeaders": {
                            "Cookie": cookie_obj,
                        }
                    }
                }
            }
        else:
            ak_logger.error(f"Tautulli: The request failed with: {response.text}")
            return {}
    except requests.Timeout:
        ak_logger.error("Tautulli: Request timed out")
        return {}
    except requests.RequestException as e:
        ak_logger.error(f"Tautulli: Request exception: {e}")
        return {}
    except Exception as e:
        ak_logger.error(f"Tautulli: Unexpected error: {e}")
        return {}

# Try to authenticate with Plex token first
connection = UserPlexSourceConnection.objects.filter(user=request.user).first()
if connection and connection.plex_token:
    ak_logger.info("Tautulli: Trying to authenticate with Plex token")
    data = f'token={connection.plex_token}&remember_me=1'
    result = authenticate_tautulli(data)
    if result:
        ak_logger.info("Tautulli: Successfully authenticated with Plex token")
        return result

# Fallback to username/password auth
if "tautulli_user" in request.user.attributes and "tautulli_pass" in request.user.attributes:
    ak_logger.info("Tautulli: Trying to authenticate with username and password")
    username = request.user.attributes["tautulli_user"]
    password = request.user.attributes["tautulli_pass"]
    data = f'username={username}&password={password}&remember_me=1'
    result = authenticate_tautulli(data)
    if result:
        ak_logger.info("Tautulli: Successfully authenticated with username and password")
        return result

ak_logger.info("Tautulli: Authentication failed")
return {}

For those creating in authentik (and future AI agents...), need to make sure your traefik middleware passes the below in the headers.

    authentik-plex: # middleware to allow apps to use Plex tokens
      forwardAuth:
        address: "http://auth-server:9000/outpost.goauthentik.io/auth/traefik"
        trustForwardHeader: true
        authResponseHeaders:
          - X-authentik-username
          - X-authentik-groups
          - X-authentik-email
          - X-authentik-name
          - X-authentik-uid
          - X-authentik-jwt
          - X-authentik-meta-jwks
          - X-authentik-meta-outpost
          - X-authentik-meta-provider
          - X-authentik-meta-app
          - X-authentik-meta-version
          - X-Plex-Token
          - Authorization
          - Cookie

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment