Python SPNEGO Authentication Library
raw JSON → 0.12.1 verified Tue May 12 auth: no python install: stale
pyspnego is a Python library designed to handle SPNEGO (Negotiate, NTLM, Kerberos) and CredSSP authentication, offering a unified interface across different operating systems. It leverages SSPI on Windows and GSSAPI on Linux, and also includes a utility for parsing raw NTLM/SPNEGO/Kerberos tokens. The library is actively maintained, with version 0.12.1 released on March 2, 2026, and follows a regular release cadence.
pip install pyspnego Warnings
breaking Support for Python 3.7 was dropped in version 0.12.0. The minimum required Python version is now 3.9+. ↓
fix Upgrade your Python environment to 3.9 or higher.
deprecated Direct imports from `spnego.gss`, `spnego.negotiate`, `spnego.ntlm`, and `spnego.sspi` are deprecated. These exports are now private. ↓
fix Use `import spnego.client` for client-side operations and `import spnego.server` for server-side operations.
deprecated The `username` and `password` properties on authentication context objects are deprecated and will return `None` in future releases. ↓
fix Avoid relying on these properties. The library's `Context` initialization methods still accept `username` and `password` as arguments, but accessing them directly on the context object is discouraged.
breaking In CredSSP contexts, the `client_credential` property has been removed. ↓
fix Retrieve delegated client credentials using `context.get_extra_info('client_credential')` instead.
gotcha When using GSSAPI on Linux, particularly with MIT krb5 versions <=1.18.2, channel bindings might fail with pure SPNEGO. This can lead to authentication failures if channel bindings are required by the acceptor. ↓
fix To work around this, set `options=spnego.NegotiateOptions.use_negotiate` when creating the context, or explicitly set `protocol` to either `ntlm` or `kerberos`.
gotcha When using explicit Kerberos credentials with MIT krb5 versions less than 1.14, the credentials might be stored in the system credential cache, making them accessible to other processes for that user. ↓
fix Upgrade MIT krb5 to at least version 1.14. Alternatively, set the `KRB5CCNAME` environment variable to a process-specific temporary file and delete it after use to ensure credentials are not stored in the default system cache.
gotcha When installing `pyspnego` or its GSSAPI-related optional dependencies on Linux, the build process might fail with a `krb5-config: not found` error if the Kerberos development libraries are not present in the system environment. ↓
fix Before installation, ensure that the Kerberos development package is installed on your system. For Debian/Ubuntu, use `apt-get install libkrb5-dev`. For RHEL/CentOS, use `yum install krb5-devel` or `dnf install krb5-devel`.
gotcha When installing the optional `gssapi` dependency for Kerberos support with `pyspnego` on minimal Linux distributions like Alpine, the build process may fail due to missing Kerberos development libraries. Specifically, the `krb5-config` command, crucial for configuring GSSAPI, is not found. ↓
fix Install the necessary Kerberos development packages before attempting to install `gssapi`. For Alpine Linux, use `apk add krb5-dev`. For Debian/Ubuntu, use `apt-get install libkrb5-dev`. For RHEL/CentOS, use `yum install krb5-devel`.
Install
pip install pyspnego[kerberos] Install compatibility stale last tested: 2026-05-12 v0.12.1 (up to date)
python os / libc variant status wheel install import disk mem side effects
3.10 alpine (musl) pyspnego wheel - - 35.4M - broken
3.10 alpine (musl) pyspnego - - - - - -
3.10 alpine (musl) kerberos build_error - - - - - -
3.10 alpine (musl) kerberos - - - - - -
3.10 slim (glibc) pyspnego wheel 2.5s - 36M - broken
3.10 slim (glibc) pyspnego - - - - - -
3.10 slim (glibc) kerberos build_error - 4.3s - - - -
3.10 slim (glibc) kerberos - - - - - -
3.11 alpine (musl) pyspnego wheel - - 37.6M - broken
3.11 alpine (musl) pyspnego - - - - - -
3.11 alpine (musl) kerberos build_error - - - - - -
3.11 alpine (musl) kerberos - - - - - -
3.11 slim (glibc) pyspnego wheel 2.4s - 38M - broken
3.11 slim (glibc) pyspnego - - - - - -
3.11 slim (glibc) kerberos build_error - 3.9s - - - -
3.11 slim (glibc) kerberos - - - - - -
3.12 alpine (musl) pyspnego wheel - - 29.4M - broken
3.12 alpine (musl) pyspnego - - - - - -
3.12 alpine (musl) kerberos build_error - - - - - -
3.12 alpine (musl) kerberos - - - - - -
3.12 slim (glibc) pyspnego wheel 2.1s - 30M - broken
3.12 slim (glibc) pyspnego - - - - - -
3.12 slim (glibc) kerberos build_error - 3.8s - - - -
3.12 slim (glibc) kerberos - - - - - -
3.13 alpine (musl) pyspnego wheel - - 29.1M - broken
3.13 alpine (musl) pyspnego - - - - - -
3.13 alpine (musl) kerberos build_error - - - - - -
3.13 alpine (musl) kerberos - - - - - -
3.13 slim (glibc) pyspnego wheel 2.1s - 30M - broken
3.13 slim (glibc) pyspnego - - - - - -
3.13 slim (glibc) kerberos build_error - 2.9s - - - -
3.13 slim (glibc) kerberos - - - - - -
3.9 alpine (musl) pyspnego wheel - - 35.6M - broken
3.9 alpine (musl) pyspnego - - - - - -
3.9 alpine (musl) kerberos build_error - - - - - -
3.9 alpine (musl) kerberos - - - - - -
3.9 slim (glibc) pyspnego wheel 3.0s - 36M - broken
3.9 slim (glibc) pyspnego - - - - - -
3.9 slim (glibc) kerberos build_error - 5.2s - - - -
3.9 slim (glibc) kerberos - - - - - -
Imports
- client wrong
import spnego.negotiatecorrectimport spnego.client - server wrong
import spnego.ntlmcorrectimport spnego.server
Quickstart last tested: 2026-04-24
import spnego
import os
# Example for a client initiating a Negotiate (SPNEGO) context
# Replace with actual credentials or environment variables
username = os.environ.get('SPNEGO_USERNAME', 'testuser')
password = os.environ.get('SPNEGO_PASSWORD', 'testpassword')
service_principal_name = os.environ.get('SPNEGO_SPN', 'HTTP@myservice.example.com')
try:
# Create a client context. 'negotiate' is the default protocol.
# For NTLM: protocol='ntlm'
# For Kerberos: protocol='kerberos' (requires system GSSAPI/Kerberos libs on Linux)
client_context = spnego.client.Context(
username=username,
password=password,
hostname=service_principal_name.split('@')[1] if '@' in service_principal_name else None,
service=service_principal_name.split('@')[0] if '@' in service_principal_name else None,
protocol='negotiate'
)
# The client typically sends an initial token
initial_token = client_context.step()
print(f"Initial SPNEGO token (base64 encoded): {initial_token.decode('utf-8')}")
# In a real scenario, this token would be sent to the server,
# which would then return a response token. The client would then
# call client_context.step(server_response_token) until complete.
except spnego.exceptions.NegotiateError as e:
print(f"Authentication error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")