tokensmith

package module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 3 Imported by: 0

README

TokenSmith

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.

Badges

REUSE statusgolangci-lint Build Release Go Reference Go Report Card OpenSSF Scorecard

Token Flow

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)

Start Here

TokenSmith provides token exchange plus Casbin-first AuthN/AuthZ middleware.

First time users:

Core documentation:

Features

  • 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 kid thumbprints for signing keys
    • Middleware enforcement of kid presence 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
  • 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

Quick Start

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-tokens

Useful first endpoints:

  • GET /health
  • GET /.well-known/jwks.json
  • POST /oauth/token

For complete startup options and environment variable precedence:

OpenCHAMI Bootstrap-First Quick Start (RFC 8693)

For most OpenCHAMI setups, start with the internal service bootstrap flow:

  1. Start TokenSmith with durable bootstrap/refresh stores.
  2. Mint an opaque bootstrap token with tokensmith bootstrap-token create using the same bootstrap store path.
  3. Inject TOKENSMITH_BOOTSTRAP_TOKEN into the caller service.
  4. Exchange at POST /oauth/token and verify access_token + refresh_token are returned.

Important:

  • Bootstrap token issuance is strictly local to the TokenSmith runtime context.
  • For Podman Quadlets (common deployment), use podman exec into the TokenSmith container when minting bootstrap tokens.

See full guide: docs/internal-service-auth.md

Project Structure

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

Local Installation

Main Service
go get github.com/openchami/tokensmith
AuthN/AuthZ Middleware

Use the main module and wire TokenSmith JWT validation with pkg/authn plus authorization with pkg/authz.

go get github.com/openchami/tokensmith

See docs/getting-started.md for the recommended middleware stack.

Testing (local developer guidance)

Recommended local verification (CI may not run all of these):

go test ./...
go test -race ./...
go vet ./...

Authorization (Casbin-first)

TokenSmith AuthZ is Casbin-first: model.conf + policy.csv + grouping.csv are the external interface.

Start here:

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:

Embedded baseline policy

TokenSmith embeds a baseline Casbin model + policy that implements the minimum OpenCHAMI RBAC roles:

  • admin: full CRUD on all resources across all services
  • operator: read/write on boot + metadata + SMD state; no delete
  • viewer: read-only access to all resources
  • service: 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.

Policy lifecycle
  • Policies are loaded at process startup.
  • No hot reload in v1: changing policy fragments requires a restart.
Modes (off → shadow → enforce)

Services SHOULD roll out authorization in stages:

  1. off: authorization disabled
  2. shadow: evaluate and emit metrics/logs, but do not block requests
  3. enforce: block denied requests (HTTP 403 with the TokenSmith error body)
Observability: policy version hash

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 enforce mode

This makes it possible to confirm exactly which policy is in effect across a fleet.

Troubleshooting checklist
  • If you changed policy fragments but behavior did not change: you likely need a restart (no hot reload).
  • Compare policy_version across 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.

Test utilities (for downstream integration tests)

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 and Configuration

Development

Prerequisites
  • Go 1.21 or later
  • Access to an OIDC provider (Keycloak, Hydra, or Authelia)
Build & Install

This project uses GoReleaser to automate releases and embed additional build metadata (commit info, build time, versioning, etc.).

1. Environment Variables

Before building, make sure to set the following environment variables to include detailed build metadata:

  • GIT_STATE: Indicates whether there are uncommitted changes. (clean if no changes, dirty if 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)
2. Installing GoReleaser

Follow the official GoReleaser installation instructions to set up GoReleaser locally.

3. Building Locally with GoReleaser

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.
Testing
# Run all tests
go test ./...

# Run specific package tests
go test ./pkg/tokenservice
go test ./pkg/authn
go test ./pkg/authz

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

See the OpenCHAMI Contributors Guide for more information.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • OpenCHAMI community
  • OIDC provider maintainers
  • Contributors and maintainers of this project

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClaimsFromContext deprecated

func ClaimsFromContext(ctx context.Context) (*token.TSClaims, error)

ClaimsFromContext returns legacy TokenSmith JWT claims stored in request context.

Deprecated: new services should prefer mapping verified claims into an authz.Principal and storing it using tokensmith.SetPrincipal, then use tokensmith.PrincipalFromContext.

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) (*authz.Principal, bool)

PrincipalFromContext returns the authorization principal stored in ctx.

Compatibility strategy (read-new then read-old):

  1. If a *authz.Principal was stored using tokensmith.SetPrincipal, return it.
  2. Else, if legacy JWT claims exist in ctx under the legacy key, derive a minimal principal from those claims.

Legacy-derived principal mapping:

  • ID: claims.Subject
  • Roles: claims.Scope

func SetPrincipal

func SetPrincipal(ctx context.Context, p *authz.Principal) context.Context

SetPrincipal stores p into ctx using TokenSmith's canonical principal context key.

Types

This section is empty.

Directories

Path Synopsis
cmd
tokenservice command
example
serviceauth command
examples
minisvc command
minisvc is a small demonstration service showing how to wire TokenSmith AuthN (JWT) + AuthZ (Casbin) middleware.
minisvc is a small demonstration service showing how to wire TokenSmith AuthN (JWT) + AuthZ (Casbin) middleware.
internal
casbinfuncs
Package casbinfuncs provides a centralized registry of Casbin matcher functions used by TokenSmith model presets.
Package casbinfuncs provides a centralized registry of Casbin matcher functions used by TokenSmith model presets.
middleware module
pkg
authz
Package authz provides a normative authorization contract and core types used by OpenCHAMI services integrating TokenSmith.
Package authz provides a normative authorization contract and core types used by OpenCHAMI services integrating TokenSmith.
authz/chi
Package chi provides chi-specific authorization middleware and route helpers implementing the TokenSmith AuthZ contract.
Package chi provides chi-specific authorization middleware and route helpers implementing the TokenSmith AuthZ contract.
authz/engine
Package engine constructs a Casbin-backed Authorizer.
Package engine constructs a Casbin-backed Authorizer.
authz/policyloader
Package policyloader loads Casbin model and policy artifacts (policy + grouping fragments) deterministically.
Package policyloader loads Casbin model and policy artifacts (policy + grouping fragments) deterministically.
authz/presets
Package presets provides convenience Casbin model presets.
Package presets provides convenience Casbin model presets.
testutil
Package testutil provides helpers for integration tests in downstream OpenCHAMI services.
Package testutil provides helpers for integration tests in downstream OpenCHAMI services.
token
Package token defines types and utilities for JWT-based authentication in microservices.
Package token defines types and utilities for JWT-based authentication in microservices.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL