OpenID support for modern servers and consumers with comprehensive authentication functionality.
npx @tessl/cli install tessl/pypi-python3-openid@3.2.0A comprehensive Python library implementing the OpenID authentication protocol for both consumers (relying parties) and servers (identity providers). This library provides complete OpenID 1.0, 1.1, and 2.0 support, enabling decentralized identity authentication for web applications with multiple storage backends and extension support.
pip install python3-openidpip install python3-openid[mysql] or pip install python3-openid[postgresql]import openidFor consumer (relying party) implementations:
from openid.consumer import consumer
from openid.consumer.discover import discover
from openid.store.filestore import FileOpenIDStoreFor server (identity provider) implementations:
from openid.server import server
from openid.store.filestore import FileOpenIDStoreFor extensions:
from openid.extensions import sreg, axfrom openid.consumer import consumer
from openid.store.filestore import FileOpenIDStore
from openid.consumer.discover import discover
# Initialize consumer with session and store
store = FileOpenIDStore('/tmp/openid_store')
openid_consumer = consumer.Consumer({}, store)
# Start authentication
user_url = "https://example.com/user"
auth_request = openid_consumer.begin(user_url)
# Redirect user to identity provider
redirect_url = auth_request.redirectURL(
realm="https://mysite.com",
return_to="https://mysite.com/openid/complete"
)
# Handle return from identity provider
query = request.GET # From your web framework
current_url = "https://mysite.com/openid/complete"
response = openid_consumer.complete(query, current_url)
if response.status == consumer.SUCCESS:
print(f"Authentication successful for {response.identity_url}")
elif response.status == consumer.FAILURE:
print(f"Authentication failed: {response.message}")from openid.server import server
from openid.store.filestore import FileOpenIDStore
# Initialize server with store
store = FileOpenIDStore('/tmp/openid_store')
openid_server = server.Server(store, op_endpoint="https://myop.com/openid")
# Handle incoming request
query = request.GET # From your web framework
openid_request = openid_server.decodeRequest(query)
if openid_request.mode == "checkid_setup":
# Authenticate user and create response
if user_authenticated:
openid_response = openid_request.answer(
allow=True,
server_url="https://myop.com/openid",
identity=user_identity_url,
claimed_id=user_claimed_id
)
else:
# Redirect to login page
passThe library follows a modular architecture with clear separation between consumer and server functionality:
Complete OpenID consumer implementation for web applications acting as relying parties. Handles the full authentication flow from discovery through response processing with support for immediate and setup modes.
class Consumer:
def __init__(self, session, store, consumer_class=None): ...
def begin(self, user_url, anonymous=False): ...
def complete(self, query, current_url): ...
class AuthRequest:
def redirectURL(self, realm, return_to=None, immediate=False): ...
def formMarkup(self, realm, return_to=None, immediate=False, form_tag_attrs=None): ...
def addExtension(self, extension_request): ...Comprehensive OpenID discovery system implementing Yadis, XRDS, and HTML-based discovery protocols. Handles service endpoint detection, URL normalization, and service type preference ordering for reliable identity provider discovery.
class OpenIDServiceEndpoint:
def usesExtension(self, extension_uri): ...
def preferredNamespace(self): ...
def supportsType(self, type_uri): ...
def compatibilityMode(self): ...
def isOPIdentifier(self): ...
def discoverURI(uri): ...
def normalizeURL(url): ...Complete OpenID server functionality for identity providers. Handles association requests, authentication requests, and verification with support for multiple session types and response encoding formats.
class Server:
def __init__(self, store, op_endpoint=None, signatoryClass=Signatory, encoderClass=SigningEncoder, decoderClass=Decoder): ...
def decodeRequest(self, query): ...
def encodeResponse(self, response): ...
def handleRequest(self, request): ...
class CheckIDRequest:
def answer(self, allow, server_url=None, identity=None, claimed_id=None): ...
def trustRootValid(self): ...
def returnToVerified(self): ...Pluggable storage system for associations and nonces with multiple backend implementations. Supports file-based, in-memory, and SQL database storage with automatic cleanup of expired data.
class OpenIDStore:
def storeAssociation(self, server_url, association): ...
def getAssociation(self, server_url, handle=None): ...
def removeAssociation(self, server_url, handle): ...
def useNonce(self, server_url, timestamp, salt): ...
class FileOpenIDStore(OpenIDStore): ...
class MemoryStore(OpenIDStore): ...
class SQLStore(OpenIDStore): ...Implementation of standard OpenID extensions including Simple Registration (SREG) for basic profile data and Attribute Exchange (AX) for flexible attribute sharing between consumers and servers.
class SRegRequest:
def __init__(self, required=None, optional=None, policy_url=None, sreg_ns_uri=ns_uri): ...
def requestField(self, field_name, required=False, strict=False): ...
def requestFields(self, field_names, required=False, strict=False): ...
class SRegResponse:
def get(self, field_name, default=None): ...
def items(self): ...
class FetchRequest:
def add(self, attribute): ...
def getRequiredAttrs(self): ...
class FetchResponse:
def getSingle(self, type_uri, default=None): ...
def get(self, type_uri): ...Handles shared secrets between consumers and servers including creation, serialization, message signing, and expiration management. Supports HMAC-SHA1 and HMAC-SHA256 association types with plain-text and Diffie-Hellman session types.
class Association:
def __init__(self, handle, secret, issued, lifetime, assoc_type): ...
def sign(self, pairs): ...
def signMessage(self, message): ...
def checkMessageSignature(self, message): ...
class SessionNegotiator:
def __init__(self, allowed_types): ...
def isAllowed(self, assoc_type, session_type): ...
def getAllowedType(self): ...OpenID protocol message handling with namespace management, encoding/decoding, and format conversion. Supports key-value form, URL encoding, and HTML form generation with proper namespace aliasing.
class Message:
def __init__(self, openid_namespace=None): ...
def fromPostArgs(cls, args): ...
def fromKVForm(cls, kvform_string): ...
def toURL(self, base_url): ...
def toKVForm(self): ...
def getArg(self, namespace, key, default=None): ...
def setArg(self, namespace, key, value): ...Essential utility functions for OpenID implementations including URI normalization, cryptographic operations, key-value form processing, logging, and Diffie-Hellman key exchange.
def urinorm(uri): ...
def autoSubmitHTML(form, title='OpenID transaction in progress'): ...
def toBase64(data): ...
def fromBase64(data): ...
class DiffieHellman:
def __init__(self, modulus, generator, private=None): ...
def getSharedSecret(self, other_public): ...# Response Status Constants
SUCCESS = 'success'
FAILURE = 'failure'
CANCEL = 'cancel'
SETUP_NEEDED = 'setup_needed'
# Association Types
all_association_types = ['HMAC-SHA1', 'HMAC-SHA256']
default_association_order = [
('HMAC-SHA256', 'no-encryption'),
('HMAC-SHA1', 'no-encryption'),
('HMAC-SHA256', 'DH-SHA256'),
('HMAC-SHA1', 'DH-SHA1'),
]
# OpenID Namespace URIs
OPENID1_NS = 'http://openid.net/signon/1.0'
OPENID2_NS = 'http://specs.openid.net/auth/2.0'
IDENTIFIER_SELECT = 'http://specs.openid.net/auth/2.0/identifier_select'
# Discovery Service Types
OPENID_1_0_NS = 'http://openid.net/signon/1.0'
OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server'
OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon'
OPENID_1_1_TYPE = 'http://openid.net/signon/1.1'
OPENID_1_0_TYPE = 'http://openid.net/signon/1.0'
# Session Types
session_types = ['DH-SHA1', 'DH-SHA256', 'no-encryption']
# SREG Extension
SREG_DATA_FIELDS = {
'nickname': 'Any UTF-8 string that the End User wants to use as a nickname.',
'email': 'The email address of the End User as specified in section 3.4.1 of [RFC2822]',
'fullname': 'UTF-8 string free text representation of the End User\'s full name.',
'dob': 'The End User\'s date of birth as YYYY-MM-DD.',
'gender': 'The End User\'s gender, "M" for male, "F" for female.',
'postcode': 'UTF-8 string free text that SHOULD conform to the End User\'s country\'s postal system.',
'country': 'The End User\'s country of residence as specified by ISO3166.',
'language': 'End User\'s preferred language as specified by ISO639.',
'timezone': 'ASCII string from TimeZone database'
}
# Exception Types
# Consumer Exceptions
class ProtocolError(Exception): ...
class DiscoveryFailure(Exception): ...
class SetupNeededError(Exception): ...
class TypeURIMismatch(Exception): ...
# Server Exceptions
class ServerError(Exception): ...
class VersionError(Exception): ...
class NoReturnToError(Exception): ...
class EncodingError(Exception): ...
class AlreadySigned(EncodingError): ...
class UntrustedReturnURL(ProtocolError): ...
class MalformedReturnURL(Exception): ...
class MalformedTrustRoot(Exception): ...
# Message Processing Exceptions
class UndefinedOpenIDNamespace(Exception): ...
class InvalidOpenIDNamespace(Exception): ...
class NamespaceAliasRegistrationError(Exception): ...
# Extension Exceptions
class SRegNamespaceError(Exception): ...
class AXError(Exception): ...
class NotAXMessage(Exception): ...
# Discovery Exceptions
class XRDSError(Exception): ...
class XRDSFetchingError(XRDSError): ...
# Trust Root Exceptions
class RealmVerificationRedirected(Exception): ...