Framework-neutral OAuth and MCP authorization primitives shared by Kritama applications.
TamaOAuth keeps protocol mechanics in one package while Memovee and Tama keep
their own persistence, identities, policy, and web layers. It supports both
sides of the planned integration: Memovee composes the authorization-server
functions and Tama composes the protected-resource functions.
The package is pre-release. Its public API may change before 1.0.0.
Included
- bounded authorization-code and refresh-token request parsing;
- PKCE
S256, exact resource binding, redirect matching, and scope handling; - OAuth protocol errors, including Dynamic Client Registration errors;
- authorization-server and protected-resource metadata builders;
- Client ID Metadata Document validation and SSRF-resistant retrieval;
- public-client and
private_key_jwtauthentication with replay callbacks; - asymmetric JWT access-token signing and verification;
- public-only JWKS publication, retrieval, validation, and key selection;
- refresh-token rotation and family-replay decisions;
- revocation and introspection request/response values;
- bounded public-client Dynamic Client Registration normalization; and
- behaviours for clocks, randomness, fetchers, replay stores, and key providers.
The package deliberately has no Phoenix, Ecto, Ash, Eventful, Memovee, or Tama dependency. Applications remain responsible for database transactions, authorization policy, consent, lifecycle state, HTTP rendering, caching, rate limits, configuration, and secret storage.
See Architecture for the complete boundary.
Installation
Until the first Hex release, use a sibling path only for local development:
def deps do
[
{:tama_oauth, path: "../tama-oauth"}
]
endAfter publication:
{:tama_oauth, "~> 0.1.0"}Examples
Validate the protocol portion of an authorization request before applying application-owned client and consent policy:
params = %{
"response_type" => "code",
"client_id" => "https://client.example/client.json",
"redirect_uri" => "https://client.example/callback",
"resource" => "https://tama.example/mcp/app",
"scope" => "mcp.message",
"state" => "opaque-client-state",
"code_challenge" => "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM",
"code_challenge_method" => "S256"
}
TamaOAuth.AuthorizationRequest.validate(params,
resource: "https://tama.example/mcp/app",
supported_scopes: ["mcp.message"]
)Publish only public key material and verify an audience-bound access token:
{:ok, jwks} = TamaOAuth.JWKS.public_document(application_signing_keys)
TamaOAuth.JWT.verify_access_token(token, jwks,
issuer: "https://memovee.example",
audience: "https://tama.example/mcp/app",
scopes: ["mcp.message"]
)For remote Client ID Metadata Documents, TamaOAuth.ClientMetadata.fetch/2
uses the package's bounded Req fetcher by default. Production applications
must still apply their own client-ID allowlist and cache the validated result.
Integration rule
Library functions return package structs, ordinary maps, tagged tuples, or
TamaOAuth.Error. An application should translate those values at its HTTP and
persistence boundaries. It should atomically apply refresh decisions and replay
claims inside its own transaction rather than treating this package as a data
store.
Development
Run the regular local check with:
mix precommit
mix precommit checks formatting, warnings-as-errors compilation, Credo in
strict mode, and the test suite. Run the static type analysis separately after
building its PLT:
mix dialyzer --plt
mix dialyzer --no-check
Validate generated documentation and package contents with:
mix docs
mix hex.build
Releasing
TamaOAuth uses Git Flow with develop as the integration branch and master
as the production branch:
feature/*branches start fromdevelopand merge back intodevelop;fix/*branches start fromdevelopand merge back intodevelop;release/*branches start fromdevelop, contain only stabilization work, and merge intomaster; andhotfix/*branches start frommasterand merge directly intomaster.
Commits use the Conventional Commits format. The highest-impact commit reaching
master controls the next semantic version:
fix:produces a patch release;feat:produces a minor release; andfeat!:,fix!:, or aBREAKING CHANGE:footer produces a breaking release. Before1.0.0, breaking changes advance the minor version.
For a normal release:
- Create
release/<planned-version>fromdevelopand perform final release fixes there. - Open a pull request from the release branch to
master. Preserve the Conventional Commit history with a merge commit. If the pull request is squash-merged, its squash title must be a Conventional Commit containing the highest required release signal. - The merge into
mastermakes Release Please open or update its generated release pull request with the next version and changelog. - Merge the generated release pull request. This creates the
vX.Y.Ztag and GitHub release, reruns every package check from the tag, and publishes the package and documentation to Hex. - Merge
masterback intodevelop, then delete the release branch.
For an urgent production correction, create hotfix/<slug> from master, use
fix: commits, and merge it into master. Complete the generated patch release
pull request, then merge master back into develop.
The release configuration bootstraps the package at 0.1.0; later releases use
the version recorded in the release manifest and the Conventional Commits
promoted to master. Only master can create tags or publish to Hex. CI
validates both protected branches and every pull request without publishing.
Before the first release, configure the repository as follows:
- Create a GitHub environment named
hex. Restrict deployments to the protectedmasterbranch, add required reviewers, prevent self-review, and disable administrator bypass where appropriate. - Save a dedicated, expiring Hex key with API write permission as the
repository secret
HEX_API_KEY. The protectedhexenvironment still gates the publishing job before it can access the repository secret. Prefer an organization key over a personal key when publishing for a Hex organization. - Protect both
developandmasterand require the CI checks before merging. - Enable Allow GitHub Actions to create and approve pull requests under
the organization and repository Settings > Actions > General pages.
Release Please uses the short-lived
GITHUB_TOKEN. Because events created by that token do not start new workflow runs, the release workflow explicitly dispatches CI for its generated pull request.
If Hex publication fails after the GitHub release exists, run the Publish
Hex workflow manually from master with that existing vX.Y.Z tag. Do not
create a new tag or change mix.exs for a retry.
License
TamaOAuth is licensed under the Apache License 2.0.