Skip to main content

Identity and access primitives: OAuth2/OIDC, SAML, passwords, JWT sessions, DPoP, TOTP, WebAuthn, and the anti-automation controls that guard them

Project description

3tears-iam

threetears.iam -- the identity and access primitives every authenticating service in the platform needs: password handling, OAuth2/OIDC, SAML, GitHub sign-in, session tokens, DPoP, TOTP, WebAuthn, and the anti-automation controls that keep all of it from being brute-forced.

Why this exists

Two services in this ecosystem grew their own identity layers independently. Both wrote argon2id password hashing with anti-enumeration timing. Both wrote a GitHub OAuth2 authorization-code flow. Both wrote a NATS-KV login throttle, a single-use SHA-256 ticket store, and a JWT mint/verify pair that pins its claim set. Neither could use the other's, because each was welded to its own database schema, its own transport, and its own config prefix.

That is the failure this package exists to stop. The protocol work -- RFC 7636 PKCE, RFC 9449 DPoP, RFC 6238 TOTP, OIDC discovery and id_token verification, SAML assertion handling, the OAuth2 code exchange -- is the same everywhere. Getting it subtly wrong is a security bug, and getting it subtly wrong twice means fixing it twice, in two repos, on two schedules, and finding out the second one was missed during an incident.

Model

The package owns protocol, crypto, and policy. It owns nobody's database schema and nobody's wire DTOs.

That line is deliberate. The two services that seeded this package disagree on almost everything below the protocol layer -- one is NATS-RPC-native with a multi-tenant Postgres identity schema, the other is a FastAPI app with its own control plane -- and any attempt to unify their persistence would have produced an abstraction neither could use. So state lives behind narrow Protocols (SingleUseTicketStore, AttemptLimiter, StateStore), with a NATS-KV implementation shipped for the common case and nothing stopping a caller from supplying its own.

Everything else follows from that:

  • Pure functions where the protocol allows it. PKCE verification, password policy, step-up freshness, claim mapping, and API-key hashing take arguments and return answers. No I/O, no clock you cannot inject, no global state.
  • Algorithms are pinned from literals, never read from the input. A DPoP proof does not get to say which algorithm verifies it. An id_token does not get to select none. This mirrors threetears.core.security.identity_token's discipline, and the pins are written so a static reader can audit them.
  • Fail closed by default, and without a side channel. A malformed stored hash is an authentication failure, not a 500. The one place a caller may choose otherwise is NatsKvAttemptLimiter's fail_open, which exists for a cheap throttle sitting in front of an authoritative check -- it defaults to closed, and a counter with nothing behind it must leave it that way. A rejected password never says which rule it broke when saying so would build an oracle. Errors carry structural reasons only -- never token strings, key material, or credentials -- so they are safe to log at a verification boundary.
  • Builds on core, does not fork it. jwk_thumbprint, build_jwks, generate_signing_keypair, ReplayGuard, RevocationGuard, WindowedCounter and seal/open_secret already exist in threetears.core. This package imports them.

Public surface

Imported per module -- threetears.iam itself exports only __version__, so reach for the submodule that owns the thing:

from threetears.iam.passwords import hash_password
from threetears.iam.tokens import SessionClaims, mint_session_token
from threetears.iam.stores.nats_kv import state_store, ticket_store
  • Passwords (.passwords, .breach) -- hash_password, verify_password, validate_new_password, normalize_password, PasswordVerifyResult, PasswordPolicyError, plus BreachCorpus for k-anonymity breach screening. argon2id for new hashes, bcrypt verify-then-upgrade for migrated ones, NFKC normalization always.
  • OAuth2 / OIDC (.pkce, .oidc, .github) -- PkceChallenge and the RFC 7636 verifier, OidcDiscoveryClient, verify_id_token, OidcIdentity, GithubOAuth2Client, GithubProfile.
  • SAML (.saml, extra: saml) -- SamlMetadataResolver, assertion identity extraction, relay-state validation.
  • Sessions (.tokens, .rotation) -- SessionClaims, mint_session_token, verify_session_token over EdDSA or HS256, mint_token_pair, TokenPair, sole_audience, and rotate_refresh_token with reuse detection.
  • Proof of possession (.dpop) -- validate_dpop_proof (RFC 9449, ES256/P-256).
  • Second factors (.totp, .webauthn) -- TOTP enrolment and verification, backup codes, and (extra: webauthn) passkey registration/assertion helpers.
  • Anti-automation (.stores, .clientip) -- the AttemptLimiter Protocol and its NatsKvAttemptLimiter implementation over threetears.core.coordination.WindowedCounter, plus resolve_client_ip for trusted-proxy-aware rate-limit keying.
  • Storage seams (.stores) -- SingleUseTicketStore and StateStore Protocols, hash_ticket/new_ticket_secret, the threetears.iam.stores.nats_kv implementations with their state_store/ticket_store factories, and in-memory doubles in threetears.iam.stores.memory for consumer tests.

Install

pip install 3tears-iam
pip install '3tears-iam[saml]'      # adds pysaml2; needs the xmlsec1 system binary
pip install '3tears-iam[webauthn]'  # adds passkey support

Versioning policy

3tears-iam versions in lockstep with the rest of the 3tears monorepo: every package shares one version, tracking the framework git tag. All packages move together.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

3tears_iam-0.20.0.tar.gz (103.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

3tears_iam-0.20.0-py3-none-any.whl (79.4 kB view details)

Uploaded Python 3

File details

Details for the file 3tears_iam-0.20.0.tar.gz.

File metadata

  • Download URL: 3tears_iam-0.20.0.tar.gz
  • Upload date:
  • Size: 103.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for 3tears_iam-0.20.0.tar.gz
Algorithm Hash digest
SHA256 63c366b479185a5bd94ae394c53fb90aa89497f134db47dba1c24d4fc72afaa8
MD5 482a980c09eacd3d4058aee07de28d6d
BLAKE2b-256 250ee46fcabe8b7029ca68cd234ab477a4264ebecbb38bf7ede45546aa3883b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for 3tears_iam-0.20.0.tar.gz:

Publisher: release.yml on pacepace/3tears

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file 3tears_iam-0.20.0-py3-none-any.whl.

File metadata

  • Download URL: 3tears_iam-0.20.0-py3-none-any.whl
  • Upload date:
  • Size: 79.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for 3tears_iam-0.20.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6e5c99993f2404f0d08e099374c1d3971bff651907a0f13315aa06d7a5a8e1e7
MD5 95ad677040262cc0d772fe9b39907d95
BLAKE2b-256 65e6eac989745ef704462902bac5e29a7987eda3e2833cbf0eac3c01555765e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for 3tears_iam-0.20.0-py3-none-any.whl:

Publisher: release.yml on pacepace/3tears

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page