TokenSmith bridges external OIDC user identity with internal identity and access management using signed JWTs. It issues TokenSmith JWTs for user and service flows and provides AuthN/AuthZ middleware for validating those tokens and enforcing policy.
sequenceDiagram
participant User
participant OIDC
participant TokenSmith
participant ServiceA
participant ServiceB
%% User Authentication Flow
User->>OIDC: Authenticate
OIDC-->>User: ID Token
User->>TokenSmith: Exchange ID Token
TokenSmith-->>User: Internal JWT
User->>ServiceA: Request with Internal JWT
%% Service-to-Service Flow
ServiceA->>TokenSmith: Request Service Token
TokenSmith-->>ServiceA: Service JWT
ServiceA->>ServiceB: Request with Service JWT
ServiceB->>ServiceB: Verify JWT (Middleware)
TokenSmith provides token exchange plus Casbin-first AuthN/AuthZ middleware.
First time users:
- Quick navigation: Which path applies to me?
- Token flows guide: Understand upstream OIDC vs local tokens
- Troubleshooting guide: Diagnose common issues
Core documentation:
- Setup and integration:
docs/getting-started.md - HTTP endpoints and wire formats:
docs/http-endpoints.md - Internal-only service-to-service quick guide:
docs/internal-service-auth.md - Middleware wiring and principal context:
docs/context-guide.md - Casbin model and policy workflow:
docs/casbin-first-guide.md - Policy loading and
policy_version:docs/authz_policy.md - Operations and rollout modes:
docs/authz_operations.md - Fabrica integration:
docs/fabrica.md - Claims reference:
docs/claim-reference.md - CLI reference:
docs/cli-reference.md - Security notes:
docs/security-notes.md
-
Identity Bridging
- Exchange external OIDC tokens for internal JWTs
- Map external identities to internal service identities
- Dynamic authorization and scope management via policy engines
- Single upstream OIDC provider at runtime (configurable without restart)
- Compatible with multiple OIDC providers (Keycloak, Hydra, Authelia, Azure AD, etc.)
-
Service-to-Service Authentication
- Secure internal service communication
- PKI-based JWT signing and verification
- Service-specific claims and scopes
- Automatic token validation
-
AuthN/AuthZ Middleware
- TokenSmith JWT validation in
pkg/authn - PKI-based signature validation with RSA, ECDSA, and JWKS key support
- RFC 7638-compliant
kidthumbprints for signing keys - Middleware enforcement of
kidpresence and RFC 7638 format - Principal extraction from verified TokenSmith claims
- Structured authentication failure logging
- Casbin-based authorization in
pkg/authz - Service-to-service authorization using TokenSmith service principals
- TokenSmith JWT validation in
-
OIDC Provider Flexibility
- Runtime reconfiguration without restart (no downtime)
- Provider validation and dry-run mode
- Support for Keycloak, Hydra, Authelia, Azure AD, and other OIDC-compliant providers
- Extensible provider interface
-
Break-Glass Access
- Local user token minting for emergency scenarios (when upstream OIDC is unavailable)
- Explicit enable flag to prevent accidental use
- Audit trail for break-glass token creation
Generate a default config and run the service:
tokensmith generate-config --config ./config.json
tokensmith serve \
--config ./config.json \
--key-dir ./keys \
--oidc-issuer https://issuer.example \
--rfc8693-bootstrap-store ./data/bootstrap-tokens \
--rfc8693-refresh-store ./data/refresh-tokensUseful first endpoints:
GET /healthGET /.well-known/jwks.jsonPOST /oauth/token
For complete startup options and environment variable precedence:
- CLI reference:
docs/cli-reference.md - Environment reference:
docs/env-reference.md - HTTP endpoints:
docs/http-endpoints.md
For most OpenCHAMI setups, start with the internal service bootstrap flow:
- Start TokenSmith with durable bootstrap/refresh stores.
- Mint an opaque bootstrap token with
tokensmith bootstrap-token createusing the same bootstrap store path. - Inject
TOKENSMITH_BOOTSTRAP_TOKENinto the caller service. - Exchange at
POST /oauth/tokenand verifyaccess_token+refresh_tokenare returned.
Important:
- Bootstrap token issuance is strictly local to the TokenSmith runtime context.
- For Podman Quadlets (common deployment), use
podman execinto the TokenSmith container when minting bootstrap tokens.
See full guide: docs/internal-service-auth.md
tokensmith/
├── cmd/
│ └── tokenservice/ # CLI entrypoint (`tokensmith`)
├── pkg/
│ ├── keys/ # Key management utilities
│ ├── authn/ # JWT validation + principal mapping middleware
│ ├── authz/ # Casbin-first authorization contract + middleware
│ ├── token/ # JWT token management
│ ├── tokenservice/ # Token exchange service
│ └── testutil/ # Public testing helpers for downstream services
├── docs/ # AuthZ contract and operations docs
├── examples/
│ └── minisvc/ # AuthN/AuthZ integration example
└── tests/
└── integration/ # End-to-end integration setup
go get github.com/openchami/tokensmithUse the main module and wire TokenSmith JWT validation with pkg/authn plus authorization with pkg/authz.
go get github.com/openchami/tokensmithSee docs/getting-started.md for the recommended middleware stack.
Recommended local verification (CI may not run all of these):
go test ./...
go test -race ./...
go vet ./...TokenSmith AuthZ is Casbin-first: model.conf + policy.csv + grouping.csv are the external interface.
Start here:
- Casbin-first guide:
docs/casbin-first-guide.md
Normative (frozen) wire behavior:
Additional normative contract text:
Operational policy loading details:
Diagnostics endpoint and startup logging guidance:
Security/threat model notes:
Fabrica integration guidance:
TokenSmith embeds a baseline Casbin model + policy that implements the minimum OpenCHAMI RBAC roles:
admin: full CRUD on all resources across all servicesoperator: read/write on boot + metadata + SMD state; no deleteviewer: read-only access to all resourcesservice: service-to-service calls (e.g., boot-service reading metadata)
Services can run with only the embedded baseline policy, or extend it with filesystem policy fragments.
- Policies are loaded at process startup.
- No hot reload in v1: changing policy fragments requires a restart.
Services SHOULD roll out authorization in stages:
- off: authorization disabled
- shadow: evaluate and emit metrics/logs, but do not block requests
- enforce: block denied requests (HTTP 403 with the TokenSmith error body)
TokenSmith computes a deterministic policy hash (policy_version) for the effective policy set.
Operators should confirm policy_version in:
- service startup logs (policy load)
- AuthZ decision logs/metrics (shadow/enforce)
- the 403 JSON error body returned by the AuthZ middleware in
enforcemode
This makes it possible to confirm exactly which policy is in effect across a fleet.
- If you changed policy fragments but behavior did not change: you likely need a restart (no hot reload).
- Compare
policy_versionacross pods to ensure the same policy is mounted everywhere. - In shadow mode, look for shadow denials in AuthZ decision metrics/logs to identify what will break when switching to enforce.
TokenSmith exposes a small public pkg/testutil package intended for service integration tests.
Stability policy:
- Best-effort stability within a major version of TokenSmith.
- No guarantees are made about internal structures or unexported behavior.
- Do not use these helpers in production code.
- CLI commands and flags:
docs/cli-reference.md - Environment variables:
docs/env-reference.md - Config schema (
groupScopes):docs/cli-reference.md
- Go 1.21 or later
- Access to an OIDC provider (Keycloak, Hydra, or Authelia)
This project uses GoReleaser to automate releases and embed additional build metadata (commit info, build time, versioning, etc.).
Before building, make sure to set the following environment variables to include detailed build metadata:
- GIT_STATE: Indicates whether there are uncommitted changes. (
cleanif no changes,dirtyif there are.) - BUILD_HOST: Hostname of the machine performing the build.
- GO_VERSION: The version of Go used.
- BUILD_USER: The username of the person or system performing the build.
Example:
export GIT_STATE=$(if git diff-index --quiet HEAD --; then echo 'clean'; else echo 'dirty'; fi)
export BUILD_HOST=$(hostname)
export GO_VERSION=$(go version | awk '{print $3}')
export BUILD_USER=$(whoami)Follow the official GoReleaser installation instructions to set up GoReleaser locally.
Use snapshot mode to build locally without releasing:
goreleaser release --snapshot --clean- The build artifacts (including embedded metadata) will be placed in the
dist/directory. - Inspect the resulting binaries to ensure the metadata was correctly embedded.
# Run all tests
go test ./...
# Run specific package tests
go test ./pkg/tokenservice
go test ./pkg/authn
go test ./pkg/authz- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See the OpenCHAMI Contributors Guide for more information.
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenCHAMI community
- OIDC provider maintainers
- Contributors and maintainers of this project