TokenSmith bridges external OIDC user identity with internal identity and access management using signed JWTs. It provides internal service-to-service identity and access management, along with a standalone chi middleware for JWT verification using PKI.
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)
-
Identity Bridging
- Exchange external OIDC tokens for internal JWTs
- Map external identities to internal service identities
- Group-based authorization and scope management
- Support for multiple OIDC providers (Keycloak, Hydra, Authelia)
-
Service-to-Service Authentication
- Secure internal service communication
- PKI-based JWT signing and verification
- Service-specific claims and scopes
- Automatic token validation
-
JWT Middleware
- Standalone chi middleware for JWT verification
- PKI-based signature validation
- Support for RSA key pairs and JWKS
- Scope-based authorization
- Service-to-service authentication
- Extensible claims handling
-
OIDC Provider Support
- Keycloak integration
- Hydra integration
- Authelia integration
- Extensible provider interface
TokenSmith can be deployed using Docker. The following environment variables can be used to configure the service:
Environment Variable | Description | Default |
---|---|---|
TOKENSMITH_ISSUER |
The issuer URL for the token service | https://tokensmith.openchami.dev |
TOKENSMITH_CLUSTER_ID |
The ID of the cluster | default-cluster |
TOKENSMITH_OPENCHAMI_ID |
The ID of the OpenCHAMI instance | default-openchami |
TOKENSMITH_CONFIG |
Path to the configuration file | /tokensmith/config.json |
TOKENSMITH_KEY_DIR |
Directory for storing JWT keys | /tokensmith/keys |
TOKENSMITH_OIDC_PROVIDER |
OIDC provider type (hydra, keycloak, authelia) | hydra |
TOKENSMITH_PORT |
HTTP server port | 8080 |
Depending on your chosen OIDC provider, you'll need to set the following credentials:
HYDRA_CLIENT_ID
- Client ID for HydraHYDRA_CLIENT_SECRET
- Client Secret for Hydra
KEYCLOAK_CLIENT_ID
- Client ID for KeycloakKEYCLOAK_CLIENT_SECRET
- Client Secret for Keycloak
AUTHELIA_CLIENT_ID
- Client ID for AutheliaAUTHELIA_CLIENT_SECRET
- Client Secret for Authelia
docker run -d \
-p 8080:8080 \
-e TOKENSMITH_ISSUER="https://tokensmith.example.com" \
-e TOKENSMITH_CLUSTER_ID="my-cluster" \
-e TOKENSMITH_OPENCHAMI_ID="my-openchami" \
-e TOKENSMITH_OIDC_PROVIDER="hydra" \
-e HYDRA_CLIENT_ID="your-client-id" \
-e HYDRA_CLIENT_SECRET="your-client-secret" \
-v /path/to/config.json:/tokensmith/config.json \
-v /path/to/keys:/tokensmith/keys \
tokensmith:latest
-
The
keys
directory is used to store JWT signing keys. Make sure to:- Mount a persistent volume for the keys directory
- Set appropriate permissions on the host directory
- Back up the keys directory regularly
-
The configuration file should be mounted from the host system and contain your group scope mappings. Tokensmith can generate a configuration file to start with:
tokensmith generate-config --config=config.json
-
For security:
- Never commit OIDC credentials to version control
- Use Docker secrets or a secure secrets management system in production
tokensmith/
├── cmd/
│ └── tokensmith/ # Main application entry point
├── pkg/
│ ├── jwt/ # JWT package (shared)
│ │ ├── oidc/ # OIDC provider implementations
│ │ │ ├── authelia/ # Authelia provider
│ │ │ ├── hydra/ # Hydra provider
│ │ │ └── keycloak/ # Keycloak provider
│ │ └── provider.go # Provider interface
│ ├── tokenservice/ # Token exchange service
│ └── middleware/ # JWT middleware (standalone)
└── example/ # Example applications
└── middleware/ # Example of middleware usage
go get github.com/openchami/tokensmith
go get github.com/openchami/tokensmith/middleware
See the middleware documentation for detailed usage instructions.
The token service can be run as a standalone application. First, generate a default configuration file:
tokensmith generate-config --config config.json
Then start the service with the configuration file:
tokensmith serve \
--provider=keycloak \
--issuer=http://tokensmith:8080 \
--port=8080 \
--cluster-id=test-cluster-id \
--openchami-id=test-openchami-id \
--config=config.json
The configuration file (JSON format) contains settings that don't change frequently:
{
"groupScopes": {
"admin": ["admin", "write", "read"],
"operator": ["write", "read"],
"viewer": ["read"],
"user": ["read"]
}
}
Configuration options:
Flag | Description | Default |
---|---|---|
--provider |
OIDC provider type (keycloak, hydra, authelia) | hydra |
--issuer |
Token issuer identifier | http://tokensmith:8080 |
--port |
HTTP server port | 8080 |
--cluster-id |
Unique identifier for this cluster | cl-F00F00F00 |
--openchami-id |
Unique identifier for this instance of OpenCHAMI | oc-F00F00F00 |
--hydra-url |
Hydra admin API URL | http://hydra:4445 |
--authelia-url |
Authelia admin API URL | http://authelia:9091 |
--keycloak-url |
Keycloak admin API URL | http://keycloak:8080 |
--keycloak-realm |
Keycloak realm | openchami |
--config |
Path to configuration file | "" |
Environment Variable | Description |
---|---|
HYDRA_CLIENT_ID |
Client ID for hydra |
HYDRA_CLIENT_SECRET |
Client Secret for hydra |
KEYCLOAK_CLIENT_ID |
Client ID for Keycloak |
KEYCLOAK_CLIENT_SECRET |
Client Secret for Keycloak |
AUTHELIA_CLIENT_ID |
Client ID for Authelia |
AUTHELIA_CLIENT_SECRET |
Client Secret for Authelia |
go get github.com/openchami/tokensmith/middleware
- 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. (
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)
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/middleware
- 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