Skip to content

Repository files navigation

hallmark-identity (Python)

Python port of Hallmark — open, IDP-agnostic identity for AI agents via OAuth 2.0 Token Exchange (RFC 8693).

Sync API, zero runtime dependencies, Python ≥3.10.

Install

pip install hallmark-identity

Quick start

from hallmark_identity import create_identity, oidc

identity = create_identity(
    idp=oidc(issuer="https://your-idp/", client_id="agent", client_secret="…"),
)

# "Who am I?" — the agent's own machine identity (client-credentials grant)
mine = identity.agent().token(audience="https://api.internal")

# "Who am I acting for?" — on behalf of a user (you bring the user's token)
on_behalf = identity.on_behalf_of(user_token).token(
    audience="https://api.github.com", scopes=["repo"],
)

import urllib.request
req = urllib.request.Request(
    "https://api.github.com/user/repos",
    headers={"authorization": f"Bearer {on_behalf.raw}"},
)

Supported IDPs

Any RFC 8693-capable OIDC provider via oidc(), plus a keycloak() convenience adapter:

from hallmark_identity import oidc, keycloak

oidc(issuer="https://login.microsoftonline.com/<tenant>/v2.0", client_id=client_id, client_secret=client_secret)
keycloak(base_url="https://kc.example", realm="agents", client_id=client_id, client_secret=client_secret)

API

Export Purpose
create_identity(idp, store=None, refresh_skew_seconds=30, http_request=None) Factory.
identity.agent().token(audience=None, scopes=None) The agent's own identity.
identity.on_behalf_of(subject_token, type="access_token").token(...) On-behalf-of a user.
oidc(...) / keycloak(...) IDP adapters.
memory_store() Default in-memory TokenStore; implement get/set to plug in Redis, etc.
parse_token, is_expired, will_expire_within Token-claim helpers.
HallmarkError, GrantError, TokenExchangeUnsupportedError Typed errors.

A returned Token exposes .raw, .sub, .act, .aud, .scope, .exp.raw is the string sent as a bearer token.

Development

uv sync                              # install deps
uv run pytest                        # unit tests
uv run pytest -c pytest-integration.ini   # opt-in, requires a running Keycloak — see tests/integration/README.md
uv run mypy src                      # typecheck
uv build                             # build sdist + wheel

License

MIT

About

Open, IDP-agnostic identity for AI agents (Python) — agent + on-behalf-of tokens via OAuth 2.0 Token Exchange (RFC 8693)

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages