scramp: SCRAM Protocol Implementation
scramp is a pure-Python implementation of the SCRAM (Salted Challenge Response Authentication Mechanism) authentication protocol. It supports various SCRAM mechanisms including SCRAM-SHA-1, SCRAM-SHA-256, SCRAM-SHA-512, SCRAM-SHA3-512, and their channel-binding ('-PLUS') variants. The library is currently at version 1.4.8 (as of January 6, 2026) and maintains an active development status with moderate release cadence.
Warnings
- breaking Version 1.2.0 introduced backward-incompatible changes to the server-side API. This update modified how authentication information is handled to enable storing derived user data (e.g., in a database) and integrate with third-party hashing libraries like `passlib`.
- gotcha `ScramClient` selects the most secure mechanism from a provided list. To use channel-binding (`-PLUS`) variants, the `channel_binding` parameter (a tuple of name and data) must be explicitly provided during `ScramClient` initialization. If `channel_binding` is `None`, `-PLUS` mechanisms will be filtered out.
- gotcha The package name `scramp` is easily confused with other Python libraries or projects (e.g., `scamp` for music, `SCAMP`/`pyscamp` for matrix profiles, `SCaMP` for metagenomics, `SCRAP` for RNA-seq, Scamp5d vision system). Ensure you are installing and importing `scramp` specifically for SCRAM protocol implementation.
Install
-
pip install scramp
Imports
- ScramClient
from scramp import ScramClient
- ScramMechanism
from scramp import ScramMechanism
Quickstart
import os
from scramp import ScramClient, ScramMechanism
# --- Server Side Setup ---
username = "user@example.com"
password = os.environ.get('SCRAMP_TEST_PASSWORD', 'test_password') # In a real app, load from secure config
# Server mechanism (stores user's SCRAM data derived from password)
# In a real application, auth_info would be retrieved from a database for the given username.
server_mechanism = ScramMechanism(password=password)
server_auth_info = server_mechanism.make_auth_info(password) # Derived data to store/retrieve for user
print("Server: Initialized SCRAM mechanism and derived auth info.")
# --- Client Side Exchange ---
client = ScramClient(
mechanisms=['SCRAM-SHA-256'], # Client offers preferred mechanisms
username=username,
password=password
)
print(f"Client: Initialized SCRAM client for user '{username}'.")
# 1. Client sends initial message
client_first_message = client.build_client_first_message()
print(f"Client: Sending client-first-message: {client_first_message}")
# 2. Server receives client-first-message and builds server-first-message
# In a real server, 'server_auth_info' would be loaded from a DB based on 'username'
server_first_message = server_mechanism.build_server_first_message(
client_first_message, server_auth_info
)
print(f"Server: Sending server-first-message: {server_first_message}")
# 3. Client receives server-first-message and builds client-final-message
client_final_message = client.build_client_final_message(server_first_message)
print(f"Client: Sending client-final-message: {client_final_message}")
# 4. Server receives client-final-message and authenticates
server_final_message = server_mechanism.build_server_final_message(
client_final_message, server_auth_info
)
if server_mechanism.authenticated:
print("Server: Client authenticated successfully!")
print(f"Server: Sending server-final-message: {server_final_message}")
else:
print("Server: Authentication failed.")
# 5. Client receives server-final-message (for verification and channel binding)
try:
client.verify_server_final_message(server_final_message)
print("Client: Server final message verified (authentication successful from client perspective).")
except ValueError as e:
print(f"Client: Server final message verification failed: {e}")